#unused #phantom #no-std

no-std phantasm

一个小型库,帮助处理变异性

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 日

#2777Rust 模式

MIT 许可证

21KB
145

phantasm

CI status crates.io documentation (docs.rs) documentation (master) LICENSE

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 带来了一些问题

  1. 方差本身很难理解,但PhantomData使得它更加难以理解。理解如下语句(在PhantomData<fn(A, B) -> B>上反对称,在B上不变)并不直观
  2. 有时在const环境中表现不佳(见下一

phantasm的命名通过使原始意图更加清晰来帮助解决第一个问题(尽管方差仍然是一个难以理解的概念),并通过在内部进行一些黑客技巧来帮助解决第二个问题。

const fn中的函数指针是不稳定的

通常的做法是用PhantomData<fn(T) -> T>使类型在T上不变。然而,如果您曾经尝试在const fn中使用它,您知道这是痛苦的(参见rust-lang/69459rust-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可能会永远保持不变。

无运行时依赖