1个不稳定版本
0.2.0 | 2023年2月7日 |
---|---|
0.1.0 |
|
1872 在 Rust模式
16KB
121 行
目的
这个包是针对ghost-cell
/ qcell
saga of cell crates的另一种尝试。它提供了对std::cell::RefCell
的替代方案,允许在编译时而不是运行时检查内部可变性。由于Rust不允许无限创建不变泛型,这总是伴随着相当大的复杂度成本。而ghost-cell
使用不变生命周期,而qcell
可以使用不变生命周期或新类型,这个包则使用const泛型usize
。
优点
与其他*cell
包一样,这个模型提供了在编译时检查内部可变性的功能。与ghost-cell
的模型不同,这个包不需要所有的借用都在闭包中存在,并且与qcell::TCell
不同,这个包允许同时进行多于三个的借用。
缺点
首先,任何包含Cell
或Token
的项目必须泛型化const ID: usize
。如果您确定例如,某个结构体的实例将始终具有ID = 3
其次,为了提供一个安全的API,必须使用TokenBuilder
结构体来构建Token
,该结构体确保ID是唯一的。将来可能会有绕过这个的方法,但请不要抱有太大期望!
第三,使用显式的usize
区分符将Cell
或Token
传递给外部crate inherently unsafe。建议发送原始值,例如使用Cell::into_inner()
。
示例
use frankencell::*;
let (token1, next) = first().unwrap().token();
let (token2, _) = next.token();
let a = Cell::new('a');
let b = Cell::new('b');
println!("{}", a.borrow(&token1));
println!("{}", b.borrow(&token2));
// The following fails to compile:
println!("{}", a.borrow(&token2));
println!("{}", b.borrow(&token1));
未来改进
目前由于 const
的工作方式,一个 const fn
在不同的调用中返回不同的值是不可能的。然而,为了生成唯一的ID,以下情况是必须可能的
const fn inc() -> usize {
// Insert magic here
}
#[test]
fn test_inc() {
assert_eq!(inc(), 0);
assert_eq!(inc(), 1);
assert_eq!(inc(), 2);
// user-facing API is now significantly better
let token_3: Token<3> = Token::next();
let token_4: Token<4> = Token::next();
}
当/如果允许在 const
上下文中进行堆分配时,这可能成为可能,但即使如此,这种模式可能永远不会得到Rust编译器的官方支持。
当/如果宏被允许保持局部状态时,这也可能是可能的(rust-lang/rust issue 44034)。
我应该使用这个吗?
可能不应该。目前这更像是概念证明。编译器还需要做大量的工作,即使如此,这也可能不是一个可行的解决方案。
如果你只是想要比 ghost-cell
和 qcell
更易用的东西,那么 cell-family
crate 似乎有一个好的方法。`cell-family` crate 似乎有一个好的方法。