Enums 有没有一种简单的方法可以使Rust中的枚举字段发生变异?

Enums 有没有一种简单的方法可以使Rust中的枚举字段发生变异?,enums,rust,pattern-matching,Enums,Rust,Pattern Matching,假设我们有一个如下所示的枚举: enum MyEnum { Field1, Field2 {x: f64, y: f64}, /* Maybe some other fields */ MyString(String), } fn main() { let mut my_enum = MyEnum::MyString("Hello, world".to_string()); let content = match my_enum

假设我们有一个如下所示的枚举:

enum MyEnum {
    Field1,
    Field2 {x: f64, y: f64},
    /* Maybe some other fields */
    MyString(String),
}
fn main() {
    let mut my_enum = MyEnum::MyString("Hello, world".to_string());
    let content = 
        match my_enum {
            MyEnum::MyString(ref mut content) => content,
            _ => unreachable!(),
        };

    /* Some actions */
    // Mutating the string
    content.push('!');

    // Printing the string
    println!("{}", content);
}
现在,我创建了子类型
MyString
的这个枚举的一个实例,在执行一些操作之后,我想对它进行变异。例如:

fn main() {
    let mut my_enum = MyEnum::MyString("Hello, world".to_string());
    /* Some actions */
    // Mutating the string
    match my_enum {
        MyEnum::MyString(ref mut content) => {
            content.push('!');
        },
        _ => {}
    }
    // Printing the string
    match my_enum {
        MyEnum::MyString(content) => {
            println!("{}", content);
        },
        _ => {}
    }
}
然而,当我们从上下文中确切地知道
my_enum
只能时,以这种方式进行匹配是相当麻烦的。我宁愿这样写(不是正确的语法):

如果,假设,
my_enum
属于子类型
Field2
,则要变异
x

my_enum@Field2.x += 1.0;
我可以这样做吗?我强烈认为答案是“否”,因为如果我从上面的匹配中删除
\u=>{}
,则类型检查器开始抱怨非穷举模式匹配:

patterns `Field1` and `Field2` not covered
虽然可以推断,
my_enum
只能是
MyString
。所谓“推断”,我的意思是编译器可以跟踪类型为
MyEnum
的所有变量,它们可以精确地包含哪些值的子类型


我在一个更大的代码中找到了一个方便的地方,尽管我想我可以用另一种方式重写它。然而,我认为编译器可能更聪明,至少应该理解在这种情况下,
MyEnum::MyString
模式是详尽的。如果上述问题的答案真的是“不”,我想,我很感兴趣的是,这个问题是否在Rust开发者之间讨论过(可能是RFCS链接?),以及是否值得提出功能请求。

从Rust 1.15.1开始,编译器无法识别特定变量在某个执行点只能是
enum
的特定变量。因此,您始终需要在其上编写详尽的
匹配

然而,一些开发人员使之生锈,使得每个
enum
变量都是它自己的类型,这将是
enum
本身的一个子类型

如果您的变体有许多数据字段,或者如果您有附加的方法,您可以考虑在<代码>结构> <代码>中包装<代码> EnUM <代码>变体的字段,并直接使用该<代码> Stutt,绕过枚举,直到您出于任何原因需要枚举。如果您只有几个字段,并且不需要调用枚举上的方法,那么您可能只需要保留一个指向每个字段的可变指针,这些字段在开始时通过一个详尽的

匹配来获得,如下所示:

enum MyEnum {
    Field1,
    Field2 {x: f64, y: f64},
    /* Maybe some other fields */
    MyString(String),
}
fn main() {
    let mut my_enum = MyEnum::MyString("Hello, world".to_string());
    let content = 
        match my_enum {
            MyEnum::MyString(ref mut content) => content,
            _ => unreachable!(),
        };

    /* Some actions */
    // Mutating the string
    content.push('!');

    // Printing the string
    println!("{}", content);
}

到目前为止,不再需要显式的
ref
ref mut
关键字。

如果您有一整段代码,其中已知变量具有特定类型,您可以将该代码放在
匹配
臂中,或者如果您只关心一个
匹配
臂,如果让
,则使用

fn main() {
    let mut my_enum = MyEnum::MyString("Hello, world".to_string());
    /* Some actions */
    if let MyEnum::MyString(ref mut content) = my_enum {
        content.push('!');
        //...
        println!("{}", content);
    }
}
或者,如果问题出在冗长的
匹配
(或者
如果让
)上,您可以编写方法使其更整洁:

impl MyEnum {
    fn push(&mut self, char c) {
        if let MyEnum::MyString(ref mut content) = *self {
            content.push(c);
        } else {
            unreachable!();
        }
    }

    // In practice print might be more generic, for example implement
    // Display
    fn print(&self) {
        if let MyEnum::MyString(ref content) = *self {
            println!("{}", content);
        }
    }
}

fn main() {
    //...
    my_enum.push('!');
    my_enum.print();
}
截至,不再需要显式的
ref
ref mut
关键字。

如果让MyEnum::MyString(ref mut content)=my_enum{content.push('!');}