Reputation: 1259
I have an enum that can hold either an encoded type (i32
) or a decoded type (String
).
My goal is to write a function that converts the enum to the decoded state, and return a reference, but I can't do it: if I change the content of the enum first, I cannot return a reference.
enum Foo {
A(i32),
B(String),
}
use Foo::*;
impl Foo {
fn get_string(&mut self) -> &str {
match self {
A(i) => {
let s = i.to_string();
*self = B(s);
&s
}
B(string) => string,
}
}
}
I get
error[E0515]: cannot return value referencing local variable `s`
--> src/lib.rs:10:9
|
10 | / match self {
11 | | A(i) => {
12 | | let s = i.to_string();
13 | | *self = B(s);
14 | | &s
| | -- `s` is borrowed here
15 | | }
16 | | B(string) => string,
17 | | }
| |_________^ returns a value referencing data owned by the current function
error[E0382]: borrow of moved value: `s`
--> src/lib.rs:14:17
|
12 | let s = i.to_string();
| - move occurs because `s` has type `String`, which does not implement the `Copy` trait
13 | *self = B(s);
| - value moved here
14 | &s
| ^^ value borrowed here after move
Is what I want to do possible? If so, how can I do it?
Upvotes: 2
Views: 1056
Reputation: 601659
The reference you return needs to point to the data inside Foo::B
, not to your local variable s
. It's easiest to do this in two steps – first do the conversion if necessary, then return the reference. After the first step it's guaranteed that *self
is Foo::B
, so we can mark the A
branch in the match as unreachable!()
.
impl Foo {
fn get_string(&mut self) -> &str {
if let A(i) = *self {
*self = B(i.to_string());
}
match *self {
A(_) => unreachable!(),
B(ref s) => s,
}
}
}
(Note that I changed pattern matching to not use "match ergonomics", since this tends to be less confusing.)
Upvotes: 3