简体   繁体   English

如何对枚举进行变异,然后返回对枚举变体的引用?

[英]How do I mutate an enum and then return a reference to an enum variant?

I have an enum that can hold either an encoded type ( i32 ) or a decoded type ( String ).我有一个可以保存编码类型( i32 )或解码类型( 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.我的目标是编写一个 function 将枚举转换为解码的 state,并返回一个引用,但我做不到:如果我先更改枚举的内容,我无法返回一个引用。

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?如果是这样,我该怎么做?

The reference you return needs to point to the data inside Foo::B , not to your local variable s .您返回的引用需要指向Foo::B中的数据,而不是您的局部变量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!() .在第一步之后,保证*selfFoo::B ,所以我们可以将匹配中的A分支标记为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.) (请注意,我将模式匹配更改为使用“匹配人体工程学”,因为这往往不那么令人困惑。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM