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 的一部分。