1 所有权

1.1 所有权

  • 每个资源(值)都有一个所有者变量
  • 任何时刻一个资源有且只有一个所有者
  • 所有者离开作用域时,资源被释放

    1.2 转移所有权

对变量进行赋值、作为参数传入函数、作为返回值从函数返回时,根据变量类型是否实现了Copy特性,有不同的行为

  • 类型实现了Copy特性:资源被复制,原变量仍然有效
  • 类型没有实现Copy特性:资源的所有权被转移,原变量失效

    1.3 Copy特性

  • 所有基础类型(整数、浮点数、字符、布尔量)都实现了Copy特性

  • 共享引用类型实现了Copy特性;独占引用类型没有实现Copy特性

无论是编译器自动为基础类型实现Copy特性,还是通过明确声明为自定义类型实现Copy特性,Copy行为都是按比特复制,这个行为不可更改

  • 全部字段都实现了Copy特性时,自定义类型可以实现Copy特性
    • 注意:是可以实现Copy特性,不是实现了Copy特性
    • 在可以实现Copy特性的前提下,可以用两种方法之一实现Copy特性
      1. 使用#[derive(Copy)]
      2. 使用impl Copy for 类型名{}:不需要提供任何方法

CloneCopy的基类型,实现Copy的类型,必须也实现Clone

  • Copy特性的使用,总是自动的,无法明确要求使用Copy特性

    1.4 Clone特性

  • 所有基础类型(整数、浮点数、字符、布尔量)都实现了Clone特性

  • 编译器自动为基础类型实现的Clone行为是按比特复制,这个行为不可改变
  • 可以为任何自定义类型用两种方式之一实现Clone
    1. 使用#[derive(Clone)]:要求自定义类型的字段都是实现了Clone的类型
    2. 使用impl Clone for 类型名{}:需要提供clone方法:fn clone(&self) -> Self,其行为可以自行定义
  • Clone行为的调用,总是手动的,编译器不会自动调用Clone特性

    1.5 CopyClone的对比

  • 相同点

    • 编译器为所有基础类型自动实现了CopyClone特性
    • 编译器为所有基础类型实现的Copy/Clone行为都是按比特复制,这个行为不可改变
    • 编译器不会自动为自定义类型实现Copy/Clone特性,必须用两种方法之一明确声明
    • 所有字段都实现了Copy/Clone特性时,可以通过#[derive]为自定义类型实现Copy/Clone特性
    • 通过#[derive]实现Copy/Clone特性时,特性行为都是按比特复制,不需要额外提供方法代码
  • 差异点
    • 只有所有字段都实现了Copy的时候,自定义类型才能够实现Copy,且Copy行为是按比特复制,这个行为不可改变
    • 无论是否所有字段都实现了Clone,都可以为自定义类型实现Clone,且通过impl Clone for 类型实现Clone时,可自定义特性行为
    • Copy特性的调用,总是自动的:赋值、作为参数传入函数、作为返回值从函数传出时,
      • 如果类型实现了Copy特性,则自动使用Copy特性
      • 如果类型没有实现Copy特性,则转移所有权
    • Clone特性的调用,总是手动的:必须明确地调用clone方法来实现对Clone特性的调用
    • CloneCopy的基础特性,实现Copy特性时,必须同时实现Clone特性;反之则不成立:实现Clone特性时,不一定需要实现Copy特性
    • 示例```rust

      [derive(Debug,Copy)]

      struct Foo { a: i32, b: bool, }

impl Clone for Foo{ // 为自定义类型实现Clone时,可自定义Clone行为 fn clone(&self) -> Self{ Foo{ a: self.a + 10, b: !self.b, } } }

fn main() { let x = Foo{ a: 1, b: true, }; // 因为实现了Copy特性,所以赋值时自动调用Copy特性,而不是转移所有权 let mut y = x; y.a = 123; let d = y.clone(); println!(“{:?}”,x);// Foo { a: 1, b: true } println!(“{:?}”,y);// Foo { a: 123, b: true } println!(“{:?}”,d);// Foo { a: 133, b: false } }

  1. <a name="218c4c6f"></a>
  2. # 2 引用与借用
  3. - 通用引用可以使用值,但不获取所有权
  4. - 因为没有所有权,所以引用离开作用域不会导致值被释放
  5. - 通过引用使用值称作借用
  6. - 引用默认是不可变的,用`mut`修饰使之成为可变引用,即可通过引用修改值
  7. - 任何时刻,一个值只能有多个不可变引用;或者一个可变引用。可变引用与不可变引用是互斥的。
  8. - 编译器会阻止野指针(dangling pointer)
  9. - 返回引用类型时通常需要生命周期注解,详见第10章
  10. - 示例```rust
  11. fn main() {
  12. let reference_to_nothing = dangle();
  13. }
  14. fn dangle() -> &String {
  15. let s = String::from("hello");
  16. &s
  17. }
  18. // 值离开作用域后被释放,但是返回的引用不会释放,这会导致引用使用已经释放的值,产生dangling pointer
  19. // Rust编译器会阻止这种情况发生,这段代码通不过编译。如果不返回引用,直接返回值,则返回时所有权被转移,不会产生野指针,编译通过。

3 切片

  • 切片是另一种没有所有权的类型,表示引用数组或者字符串的一部分
  • 切片语法为&数组/字符串变量[start..end],切片包括start指示的元素,不包括end指示的元素
  • String类型使用切片的时候,索引值表示字节偏移量,而不是字符偏移
  • 要特别注意对中文的处理:每个中文字符占3个字节。如果运行中字节偏移量不在字符边界上,则会panic
  • 示例```rust fn main() { let s = String::from(“中文Chinese”); println!(“{}”,&s[..3]);// 输出”中” for c in s.chars(){
    1. println!("{}",c);
    } } ```