3

I have the following code:

struct MyStruct<'a>{
    data: &'a str,
}

fn get<'a>(S: &'a MyStruct<'a>) -> &'a str{
    S.data
}

fn set<'a>(S: &'a mut MyStruct<'a>, x: &'a str){
    S.data = x;
}

fn main(){
    let mut S = MyStruct{data: "hello"};
    let foo: &str = get(&S);
    set(&mut S, "goodbye");
    dbg!(foo);
}

This fails to compile because let bar: &str = get(&S) takes an immutable borrow of S, and on the next line we take a mutable borrow. But we didn't borrow the whole Struct S, just the reference inside the struct. Why is the borrow still active?

I think it has something to do with the lifetime annotations in get and set. Those functions are my attempt to "desugar" how the corresponding member functions would look like. If I change the signature of get to fn get<'a, 'b>(S: &'a MyStruct<'b>) -> &'b str, the code compiles. Why does the signature affect the duration of the borrow?

1 Answer 1

8

By specifying the lifetime in get() to be fn(&'a MyStruct<'a>) -> &'a str, you say you're borrowing the whole struct for the lifetime of the string. Because the string is used after the set(), that time period includes the set(). Thus, during the set() the struct is borrowed, which is an error.

If, on the other hand, you specify it to be fn(&'b MyStruct<'a>) -> &'a str, you borrow the struct only for the get(), and return the string inside with a different lifetime.

Not the answer you're looking for? Browse other questions tagged or ask your own question.