hello2dj / blog

一些总结文章
27 stars 1 forks source link

rust:可变与不可变 #54

Open hello2dj opened 5 years ago

hello2dj commented 5 years ago

需要读者了解 rust 基本语法

不包括内部可变性,以及原始指针

示例

非引用类型

非引用类型是指本身不是引用,且不包含引用类型字段

不可变

  1. let 变量绑定就是不可变,不可变有两层:在引用类型的说明中我们更能看出这两层含义
    • 变量本身不可重新绑定
    • 绑定对象不可修改
      • 若是 struct 类型,其中的字段也不允许改变

非引用类型,若是 let 绑定则任何改动都是不允许的

let a = 23;
a = 34; // wrong 

struct Person {
    age: i32,
    name: String,
}

let p = Person { age: 32, name: "dj".to_string() };
p.age = 34; // wrong,结构体字段不允许修改
p = Person { age: 56, name: "dj".to_string() }; // 变量不可重新绑定

let vector = vec![1,2,3];
vector[0] = 2;

可变

  1. let mut 变量绑定就是可变,可变有两层
    • 变量本身可重新绑定
    • 若是 struct 类型,其中的字段也允许改变

非引用类型,若是 let mut 绑定则任何改动都是允许的

let mut b = 34;
b = 65;

struct Person {
    age: i32,
    name: String,
};
let mut p1 = Person { age: 23, name: "dj".to_string() };
p1.age = 56;
assert_eq!(p1.age, 56);
p1 = Person { age: 34, name: "dj".to_string() };

let mut vector = vec![1,2,3];
vector[0] = 2;

assert_eq!(vector[0], 2);

彩蛋示例中我们也可以看出来,rust 是支持变量重新声明的

引用类型

我们分两步

基本数据类型的引用以及不包含引用的 strcut 类型的引用

  1. 不可变引用:变量持有者无法修改被引用对象

    • 声明不可变引用
     let a = 34;
     let b = &a;
     println!("{}", b); // 我们可以打印 b
     *b = 45; // wrong 不可以改变引用对象
    
     struct Person {
         age: i32,
         name: String,
     };
    
     let p1 = Person { age: 23, name: "dj".to_string() }; // 声明并绑定 p1 变量,资源持有者
     let p2 = &p1;
     p1.age = 34; // wrong 不能修改引用对象
    
     let mut d = 45;
     let b = &d; // 这里可以看出,可变绑定可以作为不可变引用,反之不可

    如上: b 的类型就是不可变引用,还得在不可变的两层含义么?此时就更明显了。b 的类型是 &i32, b 的引用对象我们不能改变。再看 b 本身,他的声明是 不可变绑定,意味着 b 本身也不可重新绑定。

  2. 可变引用:变量持有者可以修引用对象

    • 声明可变引用

      • 被引用对象必须是可变的
     let a = 34;
     let b = &mut a; // wrong a 是不可变的
    
     let mut c = 45;
     let b = &mut c; // 正确
     *b = 23 + 34;
     assert_eq!(c, 57); // c === 57
    
     let mut d = 34;
     b = &mut d; // wrong

    那么 b 的类型就是变引用,还得在不可变的两层含义么?此时就更明显了。b 的类型是 &mut i32, b 的引用对象我可以修改。但是再看 b 本身,他的声明是 不可变绑定,意味着 b 本身也不可重新绑定。

  3. 包含引用类型的 struct

    1. 不可变复合类型包含可变引用

      struct Man<'a> {
      age: &mut 'a i32,
      name: String,
      }
      
      let mut age = 34;
      let man = Man { age: &mut age, name: "dj".to_string() };
      // man = Man { age: &mut age, name: "dj2".to_string() }; // man 不可重新赋值
      // man.age = &mut age; // man 的字段不可重新赋值
      *man.age = 354;

      这个例子是一个包含引用的结构体,他包含了可变引用。可以看到我们声明的变量 man, man 本身以及字段都是不可重新赋值的,但是由于 age 字段是可变引用,所以 man 的 age 是可以修改的。此时的 age 就好比是 let age: &mut i32 = &mut a

    2. 可变复合类型包含不可变引用

      struct Woman<'a> {
      age: &'a i32,
      name: String,
      }
      
      let mut age = 34;
      let mut age2 = 56;
      let mut woman = Woman { age: &age, name: "dj".to_string() };
      woman = Woman { age: &age, name: "dj2".to_string() }; // woman 可重新赋值
      woman.age = &mut age2; // man 的字段可重新赋值
      // *woman.age = 354; // wrong 不可以修改字段值

      从这个例子我们又可以得到一个彩蛋,可变类型是可以赋值给不可变类型的 woman.age = &mut age2

    3. 多级引用

      let a = 34;
      let b = &a;
      let c = &b; // 此时 c 的类型就是 & & i32
      
      let d = 45;
      let mut e = &d;
      let f = &mut e; // 此时 f 的类型就是 &mut &i32

总结

对于 rust 的可变与不可变要有针对性的看待,不是声明为可变类型就代表一定可变。对于基本类型是的,但对于复合类型就要看复合类型本身是否包含引用类型。

  1. 对于基本类型

    • 声明为可变即变量本身可以重新绑定,并且可以修改其内容
    • 声明为不可变则相反,都不可改变
  2. 对于复合类型

    • 声明为可变
      • 变量本身可以重新绑定
      • 内部字段也可重新绑定
      • 若内部字段是不可变引用,则内部字段内容不可修改
      • 其他则均可
    • 声明为不可变
      • 变量本身不可以重新绑定
      • 内部字段也不可重新绑定
      • 若内部字段是可变引用,则内部字段内容可以修改
      • 其他则均不可
  3. 可变引用可以赋值给不可变引用,反之不行。这也是情理之中的,既然知道他是不可变,那赋值给他也没事儿。(但真的没事儿么?)```