• Rust学习-阶段1学习总结


      学习Rust已经两周了,基本上是断断续续的在学,或者是在上下班坐公交时,或者是在ODC没事做时。现在已经学习了Rust程序设计语言的前5章,是时候做一个总结了。关于数据类型或者if else这种内容我就不在罗列了,我只说一说我感兴趣的部分。

    • 变量和可变性(variable & mutability)
    •  函数的隐式返回值
    •  理解语句(statement)和表达式(expression)的区别
    •  break可以带变量
    • 元组
    • 所有权(ownership)

     其中所有权我会重点说一下。

        先看看Rust官网的slogan,slogan往往是可以有一个更加整体的理解。
        
     

       我抽取下Key words,1. 每个人  2. 可靠且高效。“每个人”说明这门语言不会像面向machine的汇编或者C,应该具备现代语言的一些特性,泛型,反射,完善的函数库,好用的集合等等。可靠且高效,“可靠”就是说写出来的程序的漏洞会少,不会像C那样不检查下标越界,也不会产生一些常见的内存错误(doule free或者悬挂指针之类的)。当说到“高效”我想到了C++,大家都说C++的编译时间长且开发很慢(c++我没什么发言权,说的不对,诸君还请谅解),既然是高效,我想就不能仅仅是运行时间快了吧,开发时间也应该快。下面我们探讨一下我上面说的几点。

      

    1. 变量和可变性

      rust中变量默认是不可变的,也就是说下面的类似下面的赋值操作是非法的。

    fn main() {
        let a = 100;
        a = 101;
    }

      会出现这样的错误,“不能给一个不可变的变量赋值两次。”

      如果你需要一个“会变”的变量,那你需要用 mut 关键字去显式(explicitly)的声明一个变量。这么设计的原因,为什么我们需要显示的去声明一个变量为可变的?我也不知道,我猜测跟所有权有关?

    fn main() {
        let mut a = 100;
        a = 101;
    }

    2.  函数的隐式返回值

          如果函数不适用return语句进行返回的话,函数隐式的返回最后一个表达式。当然这种写法是可以选装的,你可以选择传统的return版的返回语句。

    fn add_one(num: i32)->i32 {
        num+1
    }
    
    fn main() {
        let mut a = 100;
        a = 101;
        println!("{}", add_one(a));
    }

    3. 理解语句(statement)和表达式(expression)的区别

      rust对于语句和表达式的区分比较严格,语句就是执行一些操作但并不产生结果的指令,表达式计算并产生一些值。

    let mut num = 100;  //一个赋值语句
    num = num + 1;  //语句
    num + 1   //表达式

       函数调用是一个表达式。宏调用是一个表达式。我们用来创建新作用域的大括号(代码块),{},也是一个表达式。

    let y = {
        let x = 3;
        x+1
    };

    4.  break可以带变量

      就下边那样,loop是rust中的循环,类似while(1)。  

    fn main() {
        let mut counter = 0;
        let result = loop {
            counter += 1;
            if counter == 10 {
                break counter*2;
            }
        };
        println!("The Result is {}", result);
    }

    5.  元组

      元组(tuple)类型是一个复合类型,它可以包含多种不同类型。这种类型的形式是 " (type1, type2, type3 ... ... ) "。

    let tuple1 = (1, "hello", 3.14);
    let tuple2: (i32, string, f32) = (1, "hello", 3.14);

      那么怎么去获取元组的元素呢。可以通过元组的解构(destructuring),通过解构元组我们可以把元组内的值赋给其他的变量。

    let (x, y, z) = tuple1;

      也可以使用点号(".")去直接访问元组内的元素

    let x = tuple1.0;
    let y = tuple1.1;
    let z = tuple1.2;

    6.  所有权(ownership)

      所有权是rust一个特点之一,也是rust内存管理的核心。每个值(可以理解是内存的一小块)都有一个所有者,这个所有者可以是变量。同时程序超出所有者的作用域时,所有者所有的值也会通过调用drop()函数,从而被释放。(注意drop不是通过运行时来调用的,而是在编译期就被插入了drop函数),这种做法类似于C++中的RAII机制。值得注意的是,所有权是可以被转移的,并且所有者在转移了值的所有权之后,他就会被rust认为是无效的所有者,再次使用该变量(所有者)会产生错误。

    fn foo(str_cp:String) {
        println!("{}", str_cp);    
    }
    
    fn main() {
        let str1 = String::from("hello world");  
        foo(str1);                              
        println!("{}", str1);                
    }

      在上边的例子中,我们在堆上创建了一个字符串"hello world",该字符串的所有者是变量str1,值得注意的是,将变量作为函数的形参也会转移值的所有权,因此我们当7行的函数调用返回时,str1已经是一个无效的所有者,可怜的str1,白白丢了自己的地盘,但是他也不是什么都没有收获的,这种所有权的转移,也是有好处的。

      这里我生搬硬套了一种情况,尝试说明这种所有权转移的机制是如何防止double free的情况产生的。下面是一段和上述代码段类似的代码段,可以看到这里对同一内存块进行了两次free。那么rust是如何防止这种情况产生的呢?实际上在rust中17行的情况根本就不会出现,因为str1在此时已经是无效的了,没有free它的可能性。

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    void foo(char *str) 
    {
        printf("%s
    ", str);
        free(str);
    }
    
    int main(void) 
    {
        while (1) {
            char *str1 = (char *)malloc(512);
            strncpy(str1, "hello world", 512);
            foo(str1);
            free(str1);  //double free
            printf("%s
    ", str);
        }
        return 0;
    }

      就这样,本文只是我对前几天的学习进行的一个简单的总结。很多重要的东西都没有覆盖,等我的rust用的更熟练,我会尝试出一个Rust教程。Peace。

    参考  

  • 相关阅读:
    Java基础系列1:Java基本类型与封装类型
    深入理解设计模式六大原则
    分布式系统ID生成方案汇总
    微服务入门
    Web攻击技术
    Jedis与Redisson选型对比
    Hystrix分布式系统限流、降级、熔断框架(二)
    可重入锁ReentrantLock实现原理
    Hystrix分布式系统限流、降级、熔断框架(一)
    Redis过期策略、持久化、集群与常见缓存问题
  • 原文地址:https://www.cnblogs.com/dennis-wong/p/12081543.html
Copyright © 2020-2023  润新知