0
 0 // code snippet 1
 1
 2 struct MutStr<'a >{
 3     s: &'a mut &'a str,
 4 }
 5 
 6 fn main() {
 7     let mut s: &'static str = "hello";
 8     *MutStr{
 9         s: &mut s,
10     }.s = "world";
11     println!("{}", s);
12 }

Rust Playground link of code snippet 1

The code snippnet 1 above varies from Rust for Rustacean Ch1 listing 1-11 where I use 'a to replace two lifetimes 'a and 'b , and this code can not compile, whereas I can not tell the reason:(

I can analyze some simple code such as the following one (from Programming Rust Verson 2 page 120):

 0 // code snippet 2
 1 
 2 struct S<'a> {
 3     x: &'a i32,
 4     y: &'a i32
 5 }
 6
 7 fn main() {
 8     let x = 10;
 9     let r;
10     {
11         let y = 20;
12         {
13             let s = S {x: &x, y: &y};
14             r = s.x;
15         }
16     }
17     println!("{}", r);
18 }

Rust Playground link of code snippet 2

I denote lifetime of x, y and r with 'x , 'y and 'r respectively:

'x 'y 'r
line: from 8 to 18 line: from 11 to 16 line: from 9 to 17

When instantiating s in line 13, we are requiring 'x:'a ('x outlives 'a) 'y:'a , and when assignment r = s.x happens in line 14 , we are requiring 'a:'r . Nevertheless, this is impossible for the reason that 'y:'a conflicts with 'a:'r (see table above, 'y is shorter than 'r ) so that rustc can not find a deterministic lifetime for generic lifetime 'a satisfying those conflicting conditions.

Update: I am expecting a analyze process for code snippet 1 similar to the above one, or a general inference method when encountering lifetime problems:)

I have read this article , knowing some basic concepts about variance, such as covariance invariance and contravariance . And I kind of think my question relate to that, but don't know how to use that to analyze code snippet 1.

Steve Lau
  • 658
  • 7
  • 13
  • 1
    Can you clarify exactly what you're asking about? I can see some confusion in regards to the first snippet, *"this code can not compile, whereas I can not tell the reason"*, but I don't know why you've included the second snippet since it seems your reasoning there is on the right track. – kmdreko Feb 06 '22 at 04:22
  • Is the second snippet there to show that a lifetime bound to two variables takes the lesser of the two while the first snippet seemingly does not? – kmdreko Feb 06 '22 at 04:31
  • Thx @kmdreko , I updated my post:) – Steve Lau Feb 06 '22 at 04:57

1 Answers1

2

I have read this article, knowing some basic concepts about variance, such as covariance invariance and contravariance. And I kind of think my question relate to that, but don't know how to use that to analyze code snippet 1.

You are on the right track, the difference does lie with lifetime variance. There is a table in the Rust Reference 10.5 Subtyping and Variance that I think is helpful:

Type Variance in 'a Variance in T
&'a T covariant covariant
&'a mut T covariant invariant

In your second snippet, your references are immutable meaning the lifetime associated with them can be shortened as necessary. A reference to the variable y cannot lengthen its lifetime so the reference to x must be shortened. An thus the reference bound to r is tied to the lifetime of y and therefore you get an error when you try to use r after y has gone out of scope.

In the first snippet however, you have a mutable reference to a &'a str. If you look at the table above, you'll see that types referenced by a mutable reference are invariant and since the type is itself a &'a str, that means that 'a is invariant. This means, unlike in the second snippet, the compiler can not shorten the lifetime of 'a at all. So when you try to use s to make a MutStr, the compiler sees that you're passing a &'static str that it cannot shorten, so 'a must be 'static. But then it tries to reconcile that 'a is also linked to the variable s which is not 'static, so you get the error.

kmdreko
  • 42,554
  • 6
  • 57
  • 106