本文是对Programming Rust 第9章的总结,部分代码与图片来自此书

Struct

基本用法

在rust中, struct分为三种类型,分别为named, tuple-like, unit-like

1
2
3
4
5
6
7
8
9
struct User {
    id: usize,
    name: String,
    manager: Option<Rc<User>>,
}

struct Point(usize, usize);

struct empty;

关联方法可以使用self, &self, &mut self, Box<Self>, Rc<Self>等self参数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
impl User {
    fn new(id: usize, name: String) -> Self {
        User { id: id, name: name, manager: None }
    }

    fn get_name(&self) -> String {
        self.name.clone()
    }

    fn set_name(&mut self, name: String) {
        self.name = name;
    }

    fn move_user(self) -> User {
        self
    }

    fn manage(self: Rc<Self>, user: &mut User) {
        user.manager = Some(self);
    }
}

可以这样调用这些方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
fn main() {
    let mut member = User::new(1, "jared".to_string());
    let manager = User::new(2, "jerry".to_string());
    //&mut self
    member.set_name("abc".to_string());
    //&self
    member.get_name();
    //Rc<Self>
    Rc::new(manager).manage( &mut member);
    //Box<Self>
    let m2 = Box::new(member);
    m2.get_name();
}

调用函数时, 类型会自动转换(implicit conversion), 当然是在满足规则的情况下, 一个&self是没办法自动转换成一个&mut self, 相反则是成立的

内部可变性

有的时候, 你需要在程序中共享一些struct, 比如说配置参数,由于使用Rc, 这个时候这个配置结构是不可变的。但是很多时候, 你还是希望可以修改它的某些属性, 这个时候就要用到内部可变性

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
//配置参数
struct Config {
    path: RefCell<String>,
    timeout: 5,
}

//实例
struct Instance {
    conf: Rc<RefCell<Config>>
}

//共享配置参数
 let config = Rc::new(Config{path: RefCell::new("/abc".to_string()),timeout: 5});
 let mut ins = Instance{conf: config.clone()};
 let ins2 = Instance{conf: config};

//Config本身是immutable的, 但是可以通过内部可变性,改变path的值
 let _ = ins.conf.path.borrow_mut().replace("abc", "xyz") ;
 println!("{}", ins2.conf.path.borrow());

内部可变性的问题在于, 它打破了rust编译期的借用规则, 但是在运行期,如果它同时存在一个可变引用与不可变引用,程序会panic, 也就是说在运行期它依然要遵循借用规则