Rust入门失败之Struct

Struct

  • 有三种Struct:

    • Name-Field Structs

      1
      struct Broom { name: String, height: u32 }
    • Tuple-Like Structs

      1
      struct Bounds(usize, usize);
    • Unit-Like Structs

      1
      struct Onesuch;
  • Struct的方法有三种self引用方式:

    • fn func(self): 调用这个方法时, 原struct的所有权已经被转移(move)到self中, 原引用不可用.
    • fn func(&self): 调用这个方法时, 原引用仍然拥有它的所有权, 但self不能修改自身.
    • fn func(&mut self): 同上, 但可修改.
  • 范型Struct: impl<T> Queue<T> {}这么理解: For any type T, here are some methods available on Queue<T>

  • 通过derive属性可以让struct获得某些特质能力:

    1
    2
    3
    4
    5
    #[derive(Copy, Clone, Debug, PartialEq)]
    struct Point {
    x: f64,
    y: f64
    }

Cell<T>, RefCell<T>

需要修改内部变量或引用, 使用CellRefCell来提供interior mutability.

例如下面这个场景, SpiderSenses包含对SpiderRobot的引用, 但是如果想在SpiderRobot中添加一些文件日志, 并在SpiderSenses中记录, 那么对standard File type的引用就必须是mutable.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
pub struct SpiderRobot {
species: String,
web_enabled: bool,
leg_devices: [fd::FileDesc; 8],
...
}


use std::rc::Rc;

pub struct SpiderSenses {
robot: Rc<SpiderRobot>, // <-- pointer to settings and I/O
eyes: [Camera; 32],
motion: Accelerometer,
...
}

Cell<T>

Cell<T>实际上是个包含了私有(non-pub)成员变量T的struct. 提供了显式的方法来修改内部数据.

  • Cell::new(value): 创建一个新的Cell, move value到里面.

  • cell.get(): 返回的是一个value的拷贝.

  • cell.set(value): 这个方法很特殊, 是Rust中不需要&mut self就能修改内部数据的方法, 但是由于它是显式的set, 所以允许绕过内部可变性的规则.

    1
    2
    3
    pub fn set(&self, val: T) {  // note: not "&mut self"
    ...
    }

如果说SpiderRoot需要加一个错误计数, 那么包含它的SpiderSenses不需要mut引用就可以实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
use std::cell::Cell;

pub struct SpiderRoot {
...
hardware_error_count: Cell<u32>,
...
}

impl SpiderRoot {
/// Increase the error count by 1
pub fn add_hardware_error_count(&self) {
let n = self.hardware_error_count.get();
self.hardware_error_count.set(n + 1);
}
}

但是, Cell有一点不够灵活getset操作的对象都是是copyable数据类型. 对于File等不可拷贝类型不允许. 因此需要RefCell<T>

RefCell<T>

Cell<T>类似, 但是操作的是引用.

  • RefCell::new(value): 同上

  • ref_cell.borrow(): 返回的是Ref<T>,是value的shared reference

  • ref_cell.borrow_mut(): 返回的是RefMut<T>, 是value的 mutable reference

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    pub struct SpiderRobot {
    ...
    log_file: RefCell<File>,
    ...
    }

    impl SpiderRobot {
    /// Write a line to the log file.
    pub fn log(&self, message: &str) {
    let mut file = self.log_file.borrow_mut();
    writeln!(file, "{}", message).unwrap();
    }
    }