Rust lifetime subtyping不能与Cell一起使用。

问题描述 投票:1回答:1

给定一个类型的值 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? 编译器如何追踪到它不工作?有没有一种替代方法可以让它工作?

rust lifetime
1个回答
3
投票

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>这使得它们 不变性TBox<T>Vec<T>共变T.

原因是 Vec, Box 和其他容器类结构可以共变的原因是这些容器需要有 &mut 访问权,以改变其内容,并 &mut T 本身是不变的 T. 你不能写一个像 oops 使用 down_vec -- 编译器不允许这样做。

参考文献

© www.soinside.com 2019 - 2024. All rights reserved.