Consider such two contrast examples:
fn get_value<'a>(list:&'a mut Vec<String>)->&'a mut String{
if let Some(s) = list.first_mut(){ // #1
return s;
}
list.push("hello".to_string()); // #2
list.first_mut().unwrap()
}
fn get_value<'a>(list:&'a mut Vec<String>)->&'a mut String{
if !list.is_empty(){
let s = list.first_mut().unwrap(); // #3
return s;
}
list.push("hello".to_string()); // #4
list.first_mut().unwrap()
}
The first one won't be compiled while the second one is ok. In such two examples, both s
should have the lifetime 'a
. Don't they include #2
and #4
, respectively? Why #1
conflict with the action at #2
, however, #3
does not conflict with #4
? Desugar them, we can get the following pseudo-code:
// Case 1:
'a:{
let s:&'a mut String = XXX; // ('a, mut, *list) caused by reborrow
list.push("hello".to_string()); // P1, & mut *list , deep write
...
}
// Case 2:
'a: {
{ // block of if
let s:&'a mut String = XXX; // ('a, mut, *list) caused by reborrow
}
list.push("hello".to_string()); // P2, & mut *list , deep write
...
}
In both cases, region 'a
includes P1
and P2
. According to 2094-nll - The Rust RFC Book, if the regions of the loans include the P1 and P2, they will conflict with the action at P1
and P2
, respectively. However, the result of the second case seems to say the region of the loan does not include P2
, I suppose the key point why case 1 is an error but case 2 is ok might rely on this rule
For a statement at point P in the graph, we define the "transfer function" -- that is, which loans it brings into or out of scope -- as follows:
- any loans whose region does not include P are killed;
So, I wonder why the region of the loan at #3
does not include #4
? How to correctly consider the region of a loan? It seems that the "region of a loan" is not determined by the lifetime value? I'm not sure.