PhantomData 黑魔法
&'a mut &'a ()
use std::marker::PhantomData;
pub struct Magic<'a>(PhantomData<&'a mut &'a ()>);
impl<'a> Magic<'a> {
pub fn as_ref(&'a self) -> &'a Self {
&self
}
}
fn main() {
let pin = Magic(PhantomData);
{
pin.as_ref();
}
pin;
}
error[E0505]: cannot move out of `pin` because it is borrowed
--> src/main.rs:16:5
|
14 | pin.as_ref();
| --- borrow of `pin` occurs here
15 | }
16 | pin;
| ^^^ move out of `pin` occurs here
error: aborting due to previous error
error: Could not compile `playground`.
To learn more, run the command again with --verbose.
https://play.rust-lang.org/?gist=e16426ed7dc4dbfc0665bdb39b2876fe
此处 as_ref()
之后, 就算出了作用域, 引用也没被释放, 原因就是 'a
被强行绑定为与 pin 的生命期一样了
一般情况下, Rust 允许一个长的生命期被 variant 为一个短的
但是引入可变性的一些情况下例外, &mut T
的 T
就是一个
看下面的例子
fn overwrite<'a>(input: &mut &'a str, new: &mut &'a str) {
*input = *new;
}
fn main() {
let mut forever_str: &'static str = "hello";
{
let string = String::from("world");
overwrite(&mut forever_str, &mut &*string);
}
// Oops, printing free'd memory
println!("{}", forever_str);
}
https://play.rust-lang.org/?gist=49c82fc84a3091cb1853462b221239f7
如果允许 &mut
后的类型 variant, 上面的 'static
会被降为 'a
, 就 use after free 了
所以所有提供可变性的, 比如 &mut T
, Cell<T>
, RefCell<T>
的 T
的生命期都是 invariant 的
最上面的例子里的 'a
也就被固定了