给定一个类型的值 Vec<&'static str>
我可以自由地将其转换为 Vec<&'r str>
作为 'r
的一个子区域 'static
. 这似乎对大多数类型都有效,如 Vec
、对等类型。然而,它对以下类型不起作用,如 Cell
或 RefCell
. 具体来说。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
? 编译器如何追踪到它不工作?有没有一种替代方法可以让它工作?
Cell
和 RefCell
是不同的,因为它们允许通过共享引用来改变内部值。
为了了解这一点的重要性,我们可以写一个函数,使用 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
.
原因是 Vec
, Box
和其他容器类结构可以共变的原因是这些容器需要有 &mut
访问权,以改变其内容,并 &mut T
本身是不变的 T
. 你不能写一个像 oops
使用 down_vec
-- 编译器不允许这样做。