Reputation: 31
struct Foo01<'a> {
val: u32,
str: &'a String,
}
fn mutate_and_share_01<'a>(foo: &'a mut Foo01<'a>) -> &'a Foo01<'a> {
foo
}
fn mutate_and_share_02<'a>(foo: &'a mut Foo01<'a>) -> &'a Foo01 {
foo
}
fn mutate_and_share_03<'a>(foo: &'a mut Foo01) -> &'a Foo01<'a> {
foo
}
fn main() {
let mut foo = Foo01 { val: 16, str: &String::from("Hello ") };
let foo_mut = &mut foo;
//let loan = mutate_and_share_01(foo_mut);
//let loan2 = mutate_and_share_01(foo_mut); //error
//let loan = mutate_and_share_02(foo_mut);
//let loan2 = mutate_and_share_02(foo_mut); //error
let loan = mutate_and_share_03(foo_mut);
let loan2 = mutate_and_share_03(foo_mut); //good
}
What are differences between these mutate_and_share
versions?
Upvotes: 2
Views: 156
Reputation: 42237
In cases 1 and 2, you're saying that the function borrows the structure for as long as the structure borrows its parameter:
foo: &'a mut Foo01<'a>
this says "foo is borrowed from 'a" (&'a mut
) and "foo borrows its parameter for 'a
" (Foo01<'a>
).
Meaning as far as rustc is concerned a call to this function will necessarily borrow the input forever, as the structure necessarily borrows its input for the entirety of its own lifetime, and thus you get locked out: you can't "unborrow" the input by dropping it so the second call can't work ever.
In case 3 you're relating the parameter of the output to the internal borrow which isn't really true but works well enough at least for this case. The reality is that the two lifetimes are unrelated:
fn mutate_and_share<'a, 'b>(foo: &'a mut Foo01<'b>) -> &'a Foo01<'b> {
foo
}
Also do note that your third case only works because you're never using loan
, so it's immediately dropped before the second line executes. If you do this:
let loan = mutate_and_share_03(foo_mut);
let loan2 = mutate_and_share_03(foo_mut); //good
print("{}", loan.val)
then it's not going to compile because the mutable borrows are overlapping.
Oh, and &String
is generally useless. There are use cases for &mut String
, but any time you see an immutable reference to a String
you'd be better off with an &str
. Same with &Vec<T>
, not useful, should be &[T]
.
Upvotes: 4