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 onQueue<T>
通过
derive
属性可以让struct获得某些特质能力:1
2
3
4
5
struct Point {
x: f64,
y: f64
}
Cell<T>, RefCell<T>
需要修改内部变量或引用, 使用Cell
或 RefCell
来提供interior mutability.
例如下面这个场景, SpiderSenses
包含对SpiderRobot
的引用, 但是如果想在SpiderRobot
中添加一些文件日志, 并在SpiderSenses
中记录, 那么对standard File type的引用就必须是mutable.
1 | pub struct SpiderRobot { |
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
3pub fn set(&self, val: T) { // note: not "&mut self"
...
}
如果说SpiderRoot
需要加一个错误计数, 那么包含它的SpiderSenses
不需要mut引用就可以实现:
1 | use std::cell::Cell; |
但是, Cell有一点不够灵活get
和set
操作的对象都是是copyable数据类型. 对于File等不可拷贝类型不允许. 因此需要RefCell<T>
RefCell<T>
和Cell<T>
类似, 但是操作的是引用.
RefCell::new(value)
: 同上ref_cell.borrow()
: 返回的是Ref<T>
,是value的shared referenceref_cell.borrow_mut()
: 返回的是RefMut<T>
, 是value的 mutable reference1
2
3
4
5
6
7
8
9
10
11
12
13pub 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();
}
}