10 个版本
| 0.1.8 | 2019 年 8 月 13 日 |
|---|---|
| 0.1.7 | 2019 年 5 月 13 日 |
| 0.1.5 | 2018 年 12 月 26 日 |
| 0.1.2 | 2018 年 10 月 27 日 |
| 0.0.0 | 2018 年 9 月 30 日 |
#1015 in Rust 模式
每月 47 次下载
用于 2 crates
36KB
480 行
cell
cell 是一个 crate,它提供了一个具有额外映射功能的修订版 RefCell 实现。当需要此附加功能时,它可以作为 std::cell::RefCell 的直接替换。
警告
cell 被发现存在 一个微妙的不安全性问题,目前 Rust 的版本中尚无已知的工作区。因此,不建议使用此 crate。
问题
借用 RefCell 被表示为一个 Ref。这样的 Ref 包含对 RefCell 中包含的数据的引用。要扩展借用到原始数据中的不同成员,可以使用 map 方法。使用此方法可以创建一个新的 Ref 对象,它包含对借用数据中成员的引用。
虽然在这种情况下直接引用数据成员是合适的,但在某些情况下这还不够,需要一个实际包含此引用的对象。
示例
最突出的例子是一个迭代器。虽然迭代器内部保持对迭代对象的引用,但它不仅仅是它的引用:它包含有关迭代进度状态的信息。
如果要将这样的迭代器公开给当前借用的 RefCell 中的对象,则 Ref::map 函数是不够的
struct RefStrings(RefCell<Vec<String>>);
impl RefStrings {
fn iter(&self) -> Ref<Iter<String>> {
Ref::map(self.0.borrow(), |x| x.iter())
}
}
error[E0308]: mismatched types
| Ref::map(self.0.borrow(), |x| x.iter())
| ^^^^^^^^ expected reference, found struct `std::slice::Iter`
|
= note: expected type `&_`
found type `std::slice::Iter<'_, std::string::String>`
(注意:示例中省略了必需的生命周期以简化)
解决方案
此库提供了替代的 RefCell 和 Ref 实现,通过引入另一种映射方法:map_val 来解决这个问题。此方法返回一个 RefVal 对象。RefVal 是一种新类型,类似于 Ref,但它嵌入的是它的值(类型参数 T),而不是对其的引用。相反,T 将包含对借用对象的实际引用。
在上面的例子中,需要进行的唯一更改是将 std::cell::RefCell 替换为 cell::RefCell,将 std::cell::Ref 替换为 cell::Ref,以及使用 Ref::map 而不是 Ref::map_val。
--- test.rs
+++ test.rs
@@ -1,13 +1,14 @@
-use std::cell::Ref;
-use std::cell::RefCell;
+use cell::Ref;
+use cell::RefCell;
+use cell::RefVal;
use std::slice::Iter;
struct RefStrings(RefCell<Vec<String>>);
impl RefStrings {
- fn iter<'t, 's: 't>(&'s self) -> Ref<'t, Iter<String>> {
- Ref::map(self.0.borrow(), |x| x.iter())
+ fn iter<'t, 's: 't>(&'s self) -> RefVal<'t, Iter<String>> {
+ Ref::map_val(self.0.borrow(), |x| x.iter())
}
}
类似的功能也存在于可变借用中的 RefValMut。
替代实现
已经探讨了通过特性提供此功能的方法,但尚未找到可行的解决方案。主要问题源于我们需要访问 Ref 的内部来实现此功能。这样的特性将减轻提供替代的 RefCell 和 Ref 实现的需求。
尚未找到此问题的其他解决方案,但关于可能替代方案的讨论仍然开放,作为 Rust 问题 #54776 的一部分。