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

loc*_*cka 3 rust

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

我在Syntax of Rust 生命周期说明符中找到了这个例子,它演示了我不能做的事情:

struct User<'a> {
    name: &'a str,
}

// ... impls omitted

struct ChatRoom<'a> {
    name: &'a str,
    users: HashMap<&'a str, User<'a>>,
}
Run Code Online (Sandbox Code Playgroud)

ChatRoom持有Users的地图。每个User都是一个副本,尽管其中的名称User是共享引用。TheUser和 theChatRoom具有明确的生命周期,因此当它们加入时,编译器强制Users 必须比ChatRoom它们进入的寿命更长。

但是如果 myUser是在 之后创建的ChatRoom呢?我不能使用生命周期,因为编译器会抱怨。如果我删除User之前的ChatRoom? 我也不能那样做。

可能在它之后创建或在它之前销毁的ChatRoomhold Users怎么可能?我模糊地怀疑可以用盒子来实现这一点,但 Rust 的盒子文档很差,所以我不确定。

Fra*_*gné 5

在 Rust 中,有些类型是成对出现的:借用拥有的对应物。对于字符串,借用版本是&'a str,拥有版本是String。拥有的版本没有生命周期参数,因为它们拥有所有数据。这并不意味着它们在内部不包含指针;String将其数据存储在堆上,实际String对象仅包含指向该数据的指针。

通过使用Stringinstead of &'a str,您可以避免构造顺序的问题,因为您可以自由地移动拥有的数据(只要它不是从其他地方借用的)。例如,当你创建一个User,你首先需要创建一个String,你会再进入新的User,最后你再移动UserChatRoomHashMap

struct User {
    name: String,
}

struct ChatRoom {
    name: String,
    users: HashMap<String, User>,
}
Run Code Online (Sandbox Code Playgroud)

但是,由于您需要共享引用,因此您需要将 包装String在提供该功能的类型中。如果您正在编写单线程程序,您可以使用Rc它。如果您需要从多个线程访问这些引用,则Rc行不通;你需要Arc代替。

struct User {
    name: Rc<String>,
}

struct ChatRoom {
    name: String,
    users: HashMap<String, User>,
}
Run Code Online (Sandbox Code Playgroud)

为了创建一个Rc<String>指向相同字符串的 new ,您只需clone()在第一个Rc<String>.


现在,Stringin anRc<String>是不可变的,因为Rc不提供任何方式来改变其值(不消耗Rc)。如果您需要该功能,那么您需要将其与RefCellMutexRwLock在多线程程序中)配对。

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

struct ChatRoom {
    name: String,
    users: HashMap<String, User>,
}
Run Code Online (Sandbox Code Playgroud)