4 个版本
0.1.3 | 2022 年 4 月 23 日 |
---|---|
0.1.2 | 2020 年 10 月 11 日 |
0.1.1 | 2020 年 5 月 14 日 |
0.1.0 | 2020 年 5 月 14 日 |
#2777 在 Rust 模式
21KB
145 行
phantasm
phantasm
提供了处理变异性工具。更多信息请参阅 文档。
[dependencies]
phantasm = "0.1"
编译器支持:需要 rustc 1.40+
lib.rs
:
此包旨在使处理 变异性 更加容易。该包暴露了 3 个类型 - Invariant<T>
、Covariant<T>
和 Contravariant<T>
,这些类型在 T
上的变异性与 PhantomData<_>
类似。
动机
在 Rust 中,结构体中有未使用的泛型参数是一个错误
struct Slice<'a, T> {
start: *const T,
end: *const T,
}
error[E0392]: parameter `'a` is never used
--> src/lib.rs:16:14
|
3 | struct Slice<'a, T> {
| ^^ unused parameter
|
= help: consider removing `'a`, referring to it in a field, or using a marker such as `std::marker::PhantomData`
这是错误,因为 Rust 编译器不知道 Slice
应该在 'a
上是协变、逆变还是不变。这意味着 rustc 不知道 Slice<'static, _>
是否是 Slice<'a, _>
的子类型或反之,或者都不是。请参阅 子类型和变异性 的 nomicon 章节,以获得更好的解释。
为了缓解这个问题并控制变异性,有一个名为 marker::PhantomData<T>
的类型。 PhantomData<T>
是一个零大小的类型,其行为类似于拥有 T
。
然而,PhantomData
带来了一些问题
- 方差本身很难理解,但
PhantomData
使得它更加难以理解。理解如下语句(在PhantomData<fn(A, B) -> B>
上反对称,在B
上不变)并不直观 - 有时在
const
环境中表现不佳(见下一段)
phantasm
的命名通过使原始意图更加清晰来帮助解决第一个问题(尽管方差仍然是一个难以理解的概念),并通过在内部进行一些黑客技巧来帮助解决第二个问题。
const fn
中的函数指针是不稳定的
通常的做法是用PhantomData<fn(T) -> T>
使类型在T
上不变。然而,如果您曾经尝试在const fn
中使用它,您知道这是痛苦的(参见rust-lang/69459和rust-lang/67649),因为Rust1.61.0
之前,在const fn
中的函数指针是不稳定的,更多信息请参见稳定化PR。这个crate可以帮助解决这个问题
use phantasm::Invariant;
pub struct Test<T>(Invariant<T>);
impl<T> Test<T> {
pub const fn new() -> Self {
Self(Invariant) // just works (even on old rust)
}
}
生命周期
对于生命周期的方差,请使用Lt<'l>
use phantasm::{Contravariant, Covariant, Invariant, Lt};
struct Test<'a, 'b, 'c>(Invariant<Lt<'a>>, Covariant<Lt<'b>>, Contravariant<Lt<'c>>);
比较运算符不能连用
注意:您不能将Invariant<Ty>
用作值(就像PhantomData
一样)。要创建Invariant<Ty>
值,请使用turbofish:Invariant::<Ty>
(对于Covariant<T>
和Contravariant<T>
也是如此)
// won't compile
let _ = phantasm::Invariant<i32>;
use phantasm::Invariant;
// ok
let _ = Invariant::<i32>;
// Both forms are acceptable in type position
struct NoFish<T>(Invariant<T>);
struct Turbofish<T>(Invariant<T>);
许多类型
当您需要同时设置许多类型的方差时,只需使用一个元组即可
struct Test<A, B>(phantasm::Covariant<(A, B)>);
MSRV
最小支持的rustc版本是1.40.0
。我不期望这个crate会有太大变化,因此MSRV可能会永远保持不变。