What is the difference between '&self' and '&'a self'?

前端 未结 1 1940
孤城傲影
孤城傲影 2020-12-01 22:23

I recently had an error which was simply resolved by changing

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


        
相关标签:
1条回答
  • 2020-12-01 23:07

    Lifetime 'a in fn foo(&'a self, ...) ... is defined for impl<'a>, that is it is the same for all foo calls.

    Lifetime 'a in fn get_mut<'a>(&'a mut self) ... is defined for the function. Different calls of get_mut can have different values for 'a.

    Your code

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

    is not the expansion of elided lifetime. This code ties lifetime of borrow &'a self to the lifetime of structure Foo<'a>. If Foo<'a> is invariant over 'a, then self should remain borrowed as long as 'a.

    Correct expansion of elided lifetime is

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

    This code doesn't depend on variance of structure Foo to be able to borrow self for shorter lifetimes.

    Example of differences between variant and invariant structures.

    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

    0 讨论(0)
提交回复
热议问题