为什么我可以为具有不同生命期的变量使用相同的生命周期标签?

时间:2016-04-12 14:14:14

标签: rust

为什么这段代码会编译?

#[derive(Debug)]
pub struct Foo<'a> {
    pub x: &'a [&'a str],
}

fn main() {
    let s = "s".to_string();
    let t: &str = s.as_ref();
    {
        let v = vec![t];
        let foo = Foo { x: &v[..] };
        println!("{:?}", &foo);
    }
}

在我的Foo结构中,我的x字段包含一片&strs。我对这些生命周期标签的理解是切片和个体&strs具有相同的生命周期。

但是,在我的示例中,&str t(在外部块中)与容器切片的生命周期不同(在内部块中)。

2 个答案:

答案 0 :(得分:6)

  

我对这些生命周期标签的理解是切片和个人&strs具有相同的生命周期。

这是一种常见的误解。这实际上意味着必须存在适用于两者的 a 生命周期。实例化时,Foo结构的'a对应于let v = vec![t];之后的内部块的行,因为这是两个变量共享的生命周期。

如果不存在这种灵活性,使用寿命会非常痛苦。在两条线上定义的变量具有不同的实际寿命(首先定义的变量超过定义的第二个)。如果生命周期必须实际匹配,我们总是必须在同一行上定义所有变量!

RFC #738 — Variance中提供了一些更详细的信息。

答案 1 :(得分:2)

语法'a实际上用于两种不同的情况:

  • 标记循环
  • 表示绑定

第一种情况,标记循环:

fn main() {
    'a: loop {
        println!("{}", 3);
        break 'a;
    }
}

在这里,'a清楚地描述了循环体的寿命,并允许一举破坏多层循环。

第二种更类似的情况是使用'a来表示绑定

fn<'a> susbtr(haystack: &'a str, offset: usize) -> &'a str;

在这种情况下,生命周期'a不代表变量的实际生命周期,它表示引用变量生命周期中的绑定,并允许绑在一起< / em>各种变量的界限。

请注意,调用者和被调用者以不同方式解释绑定:

  • 从调用方的角度来看,'a是一个上限,一个承诺,返回值将至少与参数一样长 (可能更长,不保证)
  • 从被调用者的角度来看(即substr),'a下限,检查任何返回的值必须至少 作为参数(可能更长,没必要)

我们可以有方差,因为绑定不代表实际生命周期,当单个绑定用于多个生命周期时,编译器将简单地推导出对该情况有意义的最低/最高边界:

  • 来电者获得最低上限可行(即保证最少)
  • 调用者获得最高下限可行(即最少约束)

例如:

fn<'b> either(one: &'b str, two: &'b str, flag: bool) -> &'b str {
    if flag { one } else { two }
}

可以通过以下方式调用:

fn<'a> call(o: &'a str, flag: bool) -> &'a str {
    either(o, "Hello, World", flag)
}

此处,o的生命周期未知(某些'a),而"Hello, World"的生命周期已知('static),'static按定义生命周期越长(它适用于所有程序)。

  • call的来电者只知道返回值的有效期至少与o
  • 一样长
  • call必须保证这一点,它会向o提供"Hello, World"either,其中'b被推断为'a之间的最低界限和'static(因此'a
  • either只需返回与其中任何一个论点一样长的东西;它没有意识到他们的生命可能会有所不同,并且不在乎