【问题标题】:What is the difference between '&self' and '&'a self'?'&self' 和 '&'a self' 和有什么不一样?
【发布时间】:2018-01-31 16:24:20
【问题描述】:

我最近遇到了一个错误,只需更改即可解决

impl<'a> Foo<'a> {
    fn foo(&'a self, path: &str) -> Boo<'a> { /* */ }
}

impl<'a> Foo<'a> {
    fn foo(&self, path: &str) -> Boo { /* */ }
}

根据我的理解,这没有意义,因为我认为第二个版本与应用生命周期省略的第一个版本完全相同。


如果我们为该方法引入一个新的生命周期,根据nomicon 中的这个示例似乎就是这种情况。

fn get_mut(&mut self) -> &mut T;                        // elided
fn get_mut<'a>(&'a mut self) -> &'a mut T;              // expanded

那么这和我第一次剪断的代码有什么区别。

【问题讨论】:

    标签: struct rust lifetime


    【解决方案1】:

    fn foo(&amp;'a self, ...) ... 中的 'a 的生命周期是为 impl&lt;'a&gt; 定义的,即所有 foo 调用都相同。

    fn get_mut&lt;'a&gt;(&amp;'a mut self) ... 中的 Lifetime 'a 是为函数定义的。 get_mut 的不同调用对于'a 可以有不同的值。

    你的代码

    impl<'a> Foo<'a> {
        fn foo(&'a self, path: &str) -> Boo<'a> { /* */ }
    }
    

    不是省略生命周期的扩展。此代码将借用 &amp;'a self 的生命周期与结构 Foo&lt;'a&gt; 的生命周期联系起来。如果Foo&lt;'a&gt;'a 上是不变的,那么self 应该一直被借用,只要'a

    省略寿命的正确展开是

    impl<'a> Foo<'a> {
        fn foo<'b>(&'b self, path: &str) -> Boo<'b> { /* */ }
    }
    

    此代码不依赖于结构的变化 Foo 能够借用 self 以缩短生命周期。

    变体和不变结构之间的差异示例。

    use std::cell::Cell;
    
    struct Variant<'a>(&'a u32);
    
    struct Invariant<'a>(Cell<&'a u32>);
    
    impl<'a> Variant<'a> {
        fn foo(&'a self) -> &'a u32 {
            self.0
        }
    }
    
    impl<'a> Invariant<'a> {
        fn foo(&'a self) -> &'a u32 {
            self.0.get()
        }
    }
    
    fn main() {
        let val = 0;
        let mut variant = Variant(&val);// variant: Variant<'long>
        let mut invariant = Invariant(Cell::new(&val));// invariant: Invariant<'long>
        {
            let r = variant.foo();
            // Pseudocode to explain what happens here
            // let r: &'short u32 = Variant::<'short>::foo(&'short variant);
            // Borrow of `variant` ends here, as it was borrowed for `'short` lifetime
    
            // Compiler can do this conversion, because `Variant<'long>` is
            // subtype of Variant<'short> and `&T` is variant over `T`
            // thus `variant` of type `Variant<'long>` can be passed into the function 
            // Variant::<'short>::foo(&'short Variant<'short>)
        }
        // variant is not borrowed here
        variant = Variant(&val);
    
        {
            let r = invariant.foo();
            // compiler can't shorten lifetime of `Invariant`
            // thus `invariant` is borrowed for `'long` lifetime
        }
        // Error. invariant is still borrowed here
        //invariant = Invariant(Cell::new(&val));
    }
    

    Playground link

    【讨论】:

    • 第二个变体告诉编译器Boo&lt;'b&gt;应该和借用&amp;'b self一样长。那是当Boo&lt;'b&gt; 不再在它被占用的词法范围内时,self 不再被借用。
    • 第一个变体将借用 &amp;'a self 的生命周期与结构 Foo&lt;'a&gt; 的生命周期联系起来。如果Foo&lt;'a&gt;invariant 超过'a,这意味着self 应该保持借用,只要'a
    • 我添加了一点解释为什么Foo 的差异会影响您的代码。
    • 太好了,现在我明白了为什么我在创建 MVCE 时失败了。我的原始结构包含一些阻止它变体的东西,而我的测试结构只包含&amp;str,它不会阻止变化。
    猜你喜欢
    • 1970-01-01
    • 2016-02-24
    • 2019-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-02
    • 1970-01-01
    • 2020-06-16
    相关资源
    最近更新 更多