如何将生命周期无法预测的另一个结构集合保存在另一个结构中?

时间:2016-05-28 15:10:35

标签: rust

我想管理另一个对象中的对象集合,但我无法预测此集合中元素的生命周期。

我在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都是副本。 UserChatRoom具有明确的生命周期,因此当它们加入时,编译器会强制User必须比他们进入的ChatRoom更长寿。

但是如果User之后我的ChatRoom被创建了怎么办?我无法使用生命周期,因为编译器会抱怨。如果我在User之前删除ChatRoom该怎么办?我也做不到。

ChatRoom如何保留User之后可能被创建或在其之前被销毁的人?我隐约怀疑用盒子可以做些什么来实现这个,但Rust的盒子文档很差,所以我不确定。

1 个答案:

答案 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(或多线程程序中的MutexRwLock)配对。

struct User {
    name: Rc<RefCell<String>>,
}

struct ChatRoom {
    name: String,
    users: HashMap<String, User>,
}