我想管理另一个对象中的对象集合,但我无法预测此集合中元素的生命周期。
我在Syntax of Rust lifetime specifier中找到了这个示例,展示了我无法做到的事情:
struct User<'a> {
name: &'a str,
}
// ... impls omitted
struct ChatRoom<'a> {
name: &'a str,
users: HashMap<&'a str, User<'a>>,
}
ChatRoom
包含User
s的地图。虽然User
中的名称是共享引用,但每个User
都是副本。 User
和ChatRoom
具有明确的生命周期,因此当它们加入时,编译器会强制User
必须比他们进入的ChatRoom
更长寿。
但是如果User
之后我的ChatRoom
被创建了怎么办?我无法使用生命周期,因为编译器会抱怨。如果我在User
之前删除ChatRoom
该怎么办?我也做不到。
ChatRoom
如何保留User
之后可能被创建或在其之前被销毁的人?我隐约怀疑用盒子可以做些什么来实现这个,但Rust的盒子文档很差,所以我不确定。
答案 0 :(得分:4)
在Rust中,有些类型成对出现:借用和拥有的对应物。对于字符串,借用的版本为&'a str
,拥有的版本为String
。拥有的版本没有生命周期参数,因为他们拥有所有数据。这并不意味着他们内部没有指针; String
将其数据存储在堆上,而实际的String
对象仅包含指向该数据的指针。
使用String
代替&'a str
,您可以避免构造顺序出现问题,因为您可以move自由拥有数据(只要它不是't}借用其他地方)。例如,当您创建User
时,首先需要创建一个String
,然后将其移至新的User
,最后移动User
进入ChatRoom
&#39; HashMap
。
struct User {
name: String,
}
struct ChatRoom {
name: String,
users: HashMap<String, User>,
}
但是,由于您需要共享引用,因此需要将String
包装在提供该功能的类型中。如果您正在编写单线程程序,则可以使用Rc
。如果您需要从多个线程访问这些引用,那么Rc
将无法工作;你需要Arc
。
struct User {
name: Rc<String>,
}
struct ChatRoom {
name: String,
users: HashMap<String, User>,
}
要创建指向同一字符串的新Rc<String>
,您只需在第一个Rc<String>
上调用clone()
方法。
现在,String
中的Rc<String>
是不可变的,因为Rc
没有提供任何改变其值的方法(不使用Rc
)。如果您需要该功能,则需要将其与RefCell
(或多线程程序中的Mutex
或RwLock
)配对。
struct User {
name: Rc<RefCell<String>>,
}
struct ChatRoom {
name: String,
users: HashMap<String, User>,
}