我有一个struct
,叫做它Book
,假设它存储了书店出售的一本书上的数据。它需要在某些数据结构(例如 with Rc
)中的许多地方引用,因此不能以正常方式可变地借用。但是,它有一些属性,比如它的价格,需要在初始化之后的某个时间填充,在对象已经有未完成的引用之后。
到目前为止,我可以想到两种方法来做到这一点,但它们都有缺点:
内部可变性:给出
Book
一个字段,例如price: RefCell<Option<i32>>
初始化到RefCell::new(Option::None)
何时Book
初始化。稍后,当我们确定这本书的价格时,我们可以使用borrow_mut
toprice
来Some(10)
代替,然后我们就可以通过borrow
它来检索它的价值。我的感觉是,一般来说,除非必要,否则人们希望避免内部可变性,而且这里似乎不应该是所有必要的。这种技术也有点尴尬
Option
,因为我们需要它,因为价格直到以后才会有价值(并且将其设置为0
或-1
同时看起来不像Rust),但这需要在某些地方使用很多match
es 或unwrap
s我们可以在逻辑上确定价格已经被填写。单独的表:根本不将价格存储在里面
Book
,而是制作一个单独的数据结构来存储它,例如price_table: HashMap<Rc<Book>, i32>
。有一个函数在确定价格时创建并填充此表,然后通过引用(可变或不可变)将其传递给需要了解或更改书籍价格的每个函数。像我一样来自 C 背景,
HashMap
感觉在速度和内存方面都是不必要的开销,因为数据已经有一个自然的位置(内部Book
)并且“应该”可以通过简单的指针追踪访问。这个解决方案还意味着我必须用一个引用的附加参数来混淆很多函数price_table
。
这两种方法中的一种在 Rust 中通常更惯用,还是有其他方法可以避免这种困境?我确实看到了Once
,但我认为这不是我想要的,因为我仍然必须在初始化时知道如何填写price
,而我不知道。
当然,在其他应用程序中,我们可能需要其他类型i32
来表示我们想要的属性,所以我希望能够处理一般情况。