Variable lifetime in matching pattern

Trying to compile the following code:

#[derive(Show)] pub enum E1 { A, B, } #[derive(Show)] pub enum E2 { X(E1), Y(i32), } impl std::fmt::String for E1 { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { std::fmt::Show::fmt(self, f) } } impl std::fmt::String for E2 { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { std::fmt::Show::fmt(self, f) } } impl std::error::Error for E2 { fn description(&self) -> &'static str { match *self { E2::X(x) => { let d: &'static str = x.description(); d }, E2::Y(_) => "Unknown error", } } } impl std::error::Error for E1 { fn description(&self) -> &'static str { match *self { E1::A => "Error A", E1::B => "Error B", } } } fn main() { } 

gives an error:

 a.rs:17:39: 17:40 error: `x` does not live long enough a.rs:17 let d: &'static str = x.description(); ^ note: reference must be valid for the static lifetime... a.rs:15:9: 21:10 note: ...but borrowed value is only valid for the match at 15:8 a.rs:15 match *self { a.rs:16 E2::X(x) => { a.rs:17 let d: &'static str = x.description(); a.rs:18 d a.rs:19 }, a.rs:20 E2::Y(_) => "Unknown error" ... a.rs:15:15: 15:20 error: cannot move out of borrowed content a.rs:15 match *self { ^~~~~ a.rs:16:19: 16:20 note: attempting to move value to here a.rs:16 E2::X(x) => { ^ a.rs:16:19: 16:20 help: to prevent the move, use `ref x` or `ref mut x` to capture value by reference a.rs:16 E2::X(x) => { ^ error: aborting due to 2 previous errors 

Changing the matching pattern to E2::X(ref x) is probably causing a more detailed error, but leaves me equally confused:

 a.rs:16:19: 16:24 error: cannot infer an appropriate lifetime for pattern due to conflicting requirements a.rs:16 E2::X(ref x) => { ^~~~~ a.rs:17:39: 17:40 note: first, the lifetime cannot outlive the expression at 17:38... a.rs:17 let d: &'static str = x.description(); ^ a.rs:17:39: 17:40 note: ...so that pointer is not dereferenced outside its lifetime a.rs:17 let d: &'static str = x.description(); ^ a.rs:15:9: 21:10 note: but, the lifetime must be valid for the match at 15:8... a.rs:15 match *self { a.rs:16 E2::X(ref x) => { a.rs:17 let d: &'static str = x.description(); a.rs:18 d a.rs:19 }, a.rs:20 E2::Y(_) => "Unknown error" ... a.rs:16:19: 16:24 note: ...so that variable is valid at time of its declaration a.rs:16 E2::X(ref x) => { ^~~~~ error: aborting due to previous error 

As I can see, x should only live until x.description() returns, but the compiler seems to want to survive the entire matching block. What for? Why does he also insist on treating x as a reference if copying would probably be more logical?

0
source share
1 answer

As for x versus ref x , x does not work because you only have a reference to self and therefore cannot derive the value E1 from it - all you can do is take a link to it.

But now the most important thing: you incorrectly defined your description method, and the Rust compiler does not warn you about this, but rather makes life unpleasant for you.

This is the actual definition of the description method:

 fn description(&self) -> &str; 

Note carefully: &str , not &'static str . The compiler should have objected to 'static in the signature, but, alas, this did not happen. (This is the topic https://github.com/rust-lang/rust/issues/21508 , filed with this issue in mind.) Typically, specifying a longer lifetime will be just fine, it will simply reduce the size to size, but in some situations it won't do what you thought it was on purpose, he changed the E1 s description method to return &str with its own lifetime, but in E2 , he still wants to return &'static str . Of course, the x reference is not 'static , so it cannot do this. Confused, huh? Do not worry, basically it's not your fault!

To fix this, remove all occurrences of 'static to match the definition of the attribute. Then, since x is inside self , the lifetime will correspond accordingly.

+2
source

Source: https://habr.com/ru/post/1015195/


All Articles