#const-generics #creation #ghost-cell #qcell

nightly frankencell

qcell和ghost-cell的替代方案,使用const泛型

1个不稳定版本

0.2.0 2023年2月7日
0.1.0 2023年2月5日

1872Rust模式

MIT 许可证

16KB
121

目的

这个包是针对ghost-cell / qcell saga of cell crates的另一种尝试。它提供了对std::cell::RefCell的替代方案,允许在编译时而不是运行时检查内部可变性。由于Rust不允许无限创建不变泛型,这总是伴随着相当大的复杂度成本。而ghost-cell使用不变生命周期,而qcell可以使用不变生命周期或新类型,这个包则使用const泛型usize

优点

与其他*cell包一样,这个模型提供了在编译时检查内部可变性的功能。与ghost-cell的模型不同,这个包不需要所有的借用都在闭包中存在,并且与qcell::TCell不同,这个包允许同时进行多于三个的借用。

缺点

首先,任何包含CellToken的项目必须泛型化const ID: usize。如果您确定例如,某个结构体的实例将始终具有ID = 3

其次,为了提供一个安全的API,必须使用TokenBuilder结构体来构建Token,该结构体确保ID是唯一的。将来可能会有绕过这个的方法,但请不要抱有太大期望!

第三,使用显式的usize区分符将CellToken传递给外部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-cellqcell 更易用的东西,那么 cell-family crate 似乎有一个好的方法。`cell-family` crate 似乎有一个好的方法。

无运行时依赖