生锈寿命错误

时间:2016-12-17 23:41:05

标签: rust lifetime

任何人都可以告诉以下代码中的生命周期错误吗? (从我的实际代码简化)我自己看了看,但我无法弄清楚出了什么问题或如何解决它。当我尝试添加Cell时出现问题,但我不确定原因。

use std::cell::Cell;

struct Bar<'a> {
    bar: &'a str,
}
impl<'a> Bar<'a> {
    fn new(foo: &'a Foo<'a>) -> Bar<'a> { Bar{bar: foo.raw} }
}

pub struct Foo<'a> {
    raw: &'a str,
    cell: Cell<&'a str>,
}
impl<'a> Foo<'a> {
    fn get_bar(&self) -> Bar { Bar::new(&self) }
}

编译器错误是

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
  --> src/foo.rs:15:32
   |
15 |     fn get_bar(&self) -> Bar { Bar::new(&self) }
   |                                ^^^^^^^^

2 个答案:

答案 0 :(得分:5)

首先,解决方案:

use std::cell::Cell;

struct Bar<'a> {
    bar: &'a str,
}
impl<'a> Bar<'a> {
    fn new(foo: &Foo<'a>) -> Bar<'a> { Bar{bar: foo.raw} }
}

pub struct Foo<'a> {
    raw: &'a str,
    cell: Cell<&'a str>,
}
impl<'a> Foo<'a> {
    fn get_bar(&self) -> Bar<'a> { Bar::new(&self) }
}

您的代码中存在两个问题。第一个是get_bar,您没有指定返回类型的生命周期。当你没有在签名中指定生命周期时,Rust并没有推断出正确的生命周期,它只是根据简单的规则盲目地填充它们。在这种特定情况下,如果fn get_bar<'b>(&'b self) -> Bar<'b>的生命周期(这是您真正想要的)是self.raw,那么您得到的有效'a 明显错误。请参阅Lifetime Elision上的Rust Book章节。

第二个问题是你将参数过度约束到Bar::new&'a Foo<'a>表示只要其借用的字符串存在,您就需要借用Foo。但是类型中的借用必须比所述类型的值更长,因此在这种情况下生命周期有效的地方'a匹配被借用的东西的整个生命周期......和 get_bar的签名冲突(您&self所说的'a一定只有'a,因为它有自己的生命周期)。简而言之:从Foo借用中删除不必要的&Foo<'a>,只留下get_bar

重新说明以上内容:Bar::new的问题在于您没有写出足够的约束,<input type="text" id="txt_name" /> <input type="button" id="bt" value="click here" /> 的问题在于您写的太多了。

答案 1 :(得分:3)

DK解释了哪些约束缺失以及原因,但我想我应该在添加Cell之前解释为什么代码工作正常。结果归结为variance inference

如果您将推断的生命周期添加到原始代码并将生命周期变量重命名为唯一,那么

struct Bar<'b> {
    bar: &'b str,
}
impl<'b> Bar<'b> {
    fn new(foo: &'b Foo<'b>) -> Bar<'b> { Bar{bar: foo.raw} }
}

pub struct Foo<'a> {
    raw: &'a str,
    cell: Cell<&'a str>,
}
impl<'a> Foo<'a> {
    fn get_bar<'c>(&'c self) -> Bar<'c> { Bar::new(&self) }
}

调用Bar::new时出现问题,因为您将&'c Foo<'a>传递给期待&'b Foo<'b>的内容。通常,Rust中的不可变类型是协变的,这意味着只要'b的生命周期比'a'更短,&Foo<'a>就可以隐式转换为&Foo<'b>。如果没有单元格,&'c Foo<'a>会转换为&'c Foo<'c>,并且传递给Bar::new并且'b ='c,所以没有问题。

但是,Cell会将内部可变性添加到Foo,这意味着协变不再是安全的。这是因为Bar可能会尝试将较短生存的'b引用分配回原始Foo,但Foo要求其保留的所有引用都对寿命更长'a。因此,内部可变性使&Foo不变,这意味着您不能再隐式缩短生命周期参数。