Rust 生命周期子类型不适用于 Cell

Rust lifetime subtyping doesn't work with Cell

给定类型 Vec<&'static str> 的值,我可以将其自由转换为 Vec<&'r str>,因为 'r'static 的子区域。这似乎适用于大多数类型,例如Vec、对等。但是,它不适用于 CellRefCell 等类型。具体来说,down_vec 编译,但 down_cell 不编译:

use std::cell::Cell;

fn down_vec<'p, 'r>(x: &'p Vec<&'static str>) -> &'p Vec<&'r str> {
    x
}


fn down_cell<'p, 'r>(x: &'p Cell<&'static str>) -> &'p Cell<&'r str> {
    x
}

报错:

error[E0308]: mismatched types
 --> src/lib.rs:9:5
  |
9 |     x
  |     ^ lifetime mismatch
  |
  = note: expected reference `&'p std::cell::Cell<&'r str>`
             found reference `&'p std::cell::Cell<&'static str>`
note: the lifetime `'r` as defined on the function body at 8:18...
 --> src/lib.rs:8:18
  |
8 | fn down_cell<'p, 'r>(x: &'p Cell<&'static str>) -> &'p Cell<&'r str> {
  |                  ^^
  = note: ...does not necessarily outlive the static lifetime

为什么这不适用于 Cell?编译器如何跟踪它不起作用?有没有替代方案可以让它发挥作用?

CellRefCell 不同,因为它们允许通过共享引用更改内部值。

要了解为什么这很重要,我们可以编写一个使用 down_cell 泄漏对已释放内存的引用的函数:

fn oops() -> &'static str {
    let cell = Cell::new("this string doesn't matter");
    let local = String::from("this string is local to oops");
    let broken = down_cell(&cell);  // use our broken function to rescope the Cell
    broken.set(&local);             // use the rescoped Cell to mutate `cell`
    cell.into_inner()               // return a reference to `local`
}                                   // uh-oh! `local` is dropped here

oops 不包含 unsafe 块,但它会编译,因此为了防止访问释放的内存,编译器必须拒绝 down_cell.

为什么会这样,类型级别的解释是因为 Cell<T>RefCell<T> 包含一个 UnsafeCell<T>,这使得它们 不变 T,而 Box<T>Vec<T>T.

协变

VecBox 和其他类似容器的结构可以协变的原因是因为这些容器需要 &mut 访问权限来改变它们的内容,而 &mut T 是本身在 T 内不变。您不能使用 down_vec 编写像 oops 这样的函数——编译器不允许这样做。

参考资料