【问题标题】:How do you combine lifetimes in rust?你如何结合生锈的寿命?
【发布时间】:2014-09-05 01:29:21
【问题描述】:

这段代码:

struct Foo<'a> {
  value: Option<&'a int>,
  parent: Option<&'a Foo<'a>>
}

impl<'a> Foo<'a> {
  fn bar<'a, 'b, 'c: 'a + 'b>(&'a self, other:&'b int) -> Foo<'c> {
    return Foo { value: Some(other), parent: Some(self) };
  }
}

fn main() {
  let e = 100i;
  {
    let f = Foo { value: None, parent: None };
    let g:Foo;
    {
       g = f.bar(&e);
    }
    // <--- g should be valid here
  }
  // 'a of f is now expired, so g should not be valid here.

  let f2 = Foo { value: None, parent: None };
  {
    let e2 = 100i;
    let g:Foo;
    {
       g = f2.bar(&e2);
    }
    // <--- g should be valid here
  }
  // 'b of e2 is now expired, so g should not be valid here.
}

编译失败,报错:

<anon>:8:30: 8:35 error: cannot infer an appropriate lifetime due to conflicting requirements
<anon>:8     return Foo { value: Some(other), parent: Some(self) };
                                      ^~~~~
<anon>:7:3: 9:4 note: consider using an explicit lifetime parameter as shown: fn bar<'a, 'b>(&'a self, other: &'b int) -> Foo<'b>
<anon>:7   fn bar<'a, 'b, 'c: 'a + 'b>(&'a self, other:&'b int) -> Foo<'c> {
<anon>:8     return Foo { value: Some(other), parent: Some(self) };
<anon>:9   }

(游戏笔:http://is.gd/vAvNFi

这显然是一个人为的例子,但这是我偶尔想做的事情。

所以...

1) 你如何结合生命周期? (即。返回一个生命周期至少为 'a 或 'b 的 Foo,以较短者为准)

2) 有没有办法为资产生命周期编译失败编写测试? (例如,尝试编译一个 #[test] 以错误的方式使用该函数并因生命周期错误而失败)

【问题讨论】:

  • (顺便说一句,帖子中的代码无法编译,并且与 playpen 链接中的代码不匹配。)
  • @dbaupp 我的错。现已修复。

标签: rust


【解决方案1】:

边界'c: 'a + 'b 表示'c 至少与'a 一样长,并且与'b 一样长。但是,在这种情况下,Foo 值恰好对'a'b 中最短的一个有效:只要任一引用后面的数据超出范围,整个Foo 就必须失效。 (这就是说对'c 有效的数据在'a'b联合 中有效。)

更具体的说法,比如'b = 'static,那么'c: 'a + 'static意味着'c也必须是'static,所以返回值是Foo&lt;'static&gt;。这显然是不对的,因为它会将有限的 'a self 引用“升级”为永远存在的引用。

这里的正确行为是取生命周期的交集:Foo 仅在两个函数参数都有效时才有效。交集操作只是标记具有相同名称的引用:

fn bar<'a>(&'a self, other: &'a int) -> Foo<'a>

【讨论】:

  • 我已经编辑了我的答案,将“最大”(联合)替换为“最小”(交叉点)。但是,既然 bar 在这里是一个方法,那么在方法上省略 'a 生命周期参数并使用 impl 中的 'a 不是更好吗?我知道它在实现 trait 时会导致错误(生命周期参数必须与 trait 中定义的参数匹配),但这只是一个简单的impl,所以这两个选项都有效。
  • @FrancisGagné:至少我同意你的看法。该函数似乎不需要任何新的生命周期参数。
【解决方案2】:

删除bar 上的所有时间参数,并改用impl 中的'a 生命周期参数。

impl<'a> Foo<'a> {
  fn bar(&'a self, other:&'a int) -> Foo<'a> {                  // '
    return Foo { value: Some(other), parent: Some(self) };
  }
}

'a 将被编译器推断为所有引用都有效的最小生命周期。

【讨论】:

    猜你喜欢
    • 2014-10-25
    • 1970-01-01
    • 1970-01-01
    • 2019-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-25
    • 1970-01-01
    相关资源
    最近更新 更多