摆弄生命周期:对生命周期不安全重新解释的健全性检查

Nub*_*rke 3 unsafe lifetime rust

假设您有 的Vec实例的两个集合(此处为简单起见)T,以及一个用于计算这些集合中的元素是否出现在其中一个或两个集合中的函数:

// With lifetimes not yet annotated
fn comm(left: &Vec<T>, right: &Vec<T>) -> Vec<(Tag, &T)> {}

enum Tag {
    Left,
    Both,
    Right,
}
Run Code Online (Sandbox Code Playgroud)

comm(l,r) 保证返回的引用指向left集合的元素,无论T是出现在leftonly中还是 T出现在 Both 中。

然而,因为有些T可能出现在rightonly 中,所以函数的完整签名必须如下所示:

fn comm<'a, 'b, 'c>(left: &'a Vec<T>, right: &'b Vec<T>) -> Vec(Tag, &'c T)
where
  'a: 'c,
  'b: 'c,
Run Code Online (Sandbox Code Playgroud)

(tag, &T)那么,实际的问题是:我知道,在返回的元组之一中comm, if tag == Left or tag == Both, then肯定&T会指向集合。left

使用mem::transmute或其他机制来获取返回的引用之一comm并将其转换为与left集合匹配的生命周期是否理智、安全且合法?

例如:

fn last_common<'a, 'b>(left: &'a Vec<T>, right: &'b Vec<T>) -> &'a T {
  let tagged = comm(left, right);
  let (tag, ref_to_T) = boring code that picks one tuple from tagged...
  assert!(matches!(tag, Tag::Left) || matches!(tag, Tag::Both))
  return std::mem::transmute::<&'_ T, &'a T>(ref_to_T);
}
Run Code Online (Sandbox Code Playgroud)

Cha*_*man 5

是的,这是声音。事实上,官方文档说它transmute()可以用来延长寿命:

https://doc.rust-lang.org/stable/std/mem/fn.transmute.html#examples

延长寿命,或缩短不变寿命。这是高级的、非常不安全的 Rust!

struct R<'a>(&'a i32);
unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> {
    std::mem::transmute::<R<'b>, R<'static>>(r)
}

unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>)
                                             -> &'b mut R<'c> {
    std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r)
}
Run Code Online (Sandbox Code Playgroud)

但我不会推荐它。相反,我建议您使用枚举:

fn comm<'a, 'b, T>(left: &'a Vec<T>, right: &'b Vec<T>) -> Vec<Tag<'a, 'b, T>> {}

enum Tag<'a, 'b, T> {
    Left(&'a T),
    Both(&'a T), // Could be `&'b T`, too.
    Right(&'b T),
}
Run Code Online (Sandbox Code Playgroud)

您还可以使用一种方法来提取生命周期较短的值,例如:

impl<'a, T> Tag<'a, 'a, T> {
    pub fn value(self) -> &'a T {
        let (Self::Left(v) | Self::Right(v) | Self::Both(v)) = self;
        v
    }
}
Run Code Online (Sandbox Code Playgroud)