#refcell #replace #mapping #borrow #state #advanced #borrowed

cell

std::cell::RefCell 的替代品,增加了对映射借用的高级支持

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

MIT/Apache

36KB
480

pipeline crates.io Docs rustc

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>`

(注意:示例中省略了必需的生命周期以简化)

解决方案

此库提供了替代的 RefCellRef 实现,通过引入另一种映射方法: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 的内部来实现此功能。这样的特性将减轻提供替代的 RefCellRef 实现的需求。

尚未找到此问题的其他解决方案,但关于可能替代方案的讨论仍然开放,作为 Rust 问题 #54776 的一部分。

无运行时依赖