iovxw

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 TT 就是一个

看下面的例子

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 也就被固定了