Suppose we have an enum that looks like this:
enum MyEnum {
Field1,
Field2 {x: f64, y: f64},
/* Maybe some other fields */
MyString(String),
}
Now I created an instance of this enum of the subtype MyString
and after some actions I want to mutate it. For example:
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);
},
_ => {}
}
}
However, matching in such a way is pretty cumbersome when we know exactly from the context that my_enum
can be only MyString
. I would rather write something like this (not a correct Rust syntax):
[email protected]('!');
println!("{}", my_enum@MyString);
And if, suppose, my_enum
is of the subtype Field2
, then to mutate x
:
[email protected] += 1.0;
Can I do something like this? I strongly suppose that the answer is "No", because if I remove _ => {}
from the matches above, type checker starts complaining about non-exhaustive pattern matching:
patterns `Field1` and `Field2` not covered
though it can be inferred that my_enum
can be nothing but MyString
. By "inferred" I mean the compiler could track for all the variables of the type MyEnum
what subtypes of values they can contain exactly.
I found a place in a larger code where this could be convenient, though I guess I can rewrite it in other way. However, I think that the compiler could be smarter and at least understand that in this context the pattern MyEnum::MyString
is exhaustive. If the answer on the question above is really "No", as I suspect, I'm interested if this issue was discussed among Rust developers (maybe a RFCS link?) and if it is worth to make a feature request.
The easiest way to convert an enum to a String in Rust is to implement the std::fmt::Display trait. Then you can call the to_string() method.
Adding data to enum variantsCreated a new instance of the enum and assigned it to a variable. Put that variable in a match statement. Destructured the contents of each enum variant into a variable within the match statement.
In Rust, methods cannot only be defined on structs, they can also be defined on tuples and enums, and even on built-in types like integers.
An enum in Rust is a custom data type that represents data that can be anyone among several possible variants. Each variant in the enum can optionally have data associated with it. An enumerated type is defined using the enum keyword before the name of the enumeration.
As of Rust 1.15.1, the compiler won't recognize that a particular variable can only be a particular variant of an enum
at some point of execution. As such, you always need to write an exhaustive match
on it.
However, some Rust developers have been considering making it such that each enum
variant would be its own type, which would be a subtype of the enum
itself.
If your variant has many data fields, or if you have methods attached to it, you could consider wrapping the enum
variant's fields in a struct
and use that struct
directly, bypassing the enum entirely until you do need the enum for whatever reason. If you have only a few fields, and don't need to call methods on the enum, then you might be able to get away with just keeping a mutable pointer to each field that you obtain at the beginning with an exhaustive match
, like this:
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);
}
As of Rust 1.26, the explicit ref
and ref mut
keywords are no longer required.
If you have an entire section of code in which the variable is known to have a particular type, you could just put that code inside the match
, or if there's only one match
arm which you care about, use if let
:
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);
}
}
Alternatively, if it's just the verbose match
(or if let
) which is the problem, you can write methods to make it tidier:
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();
}
As of Rust 1.26, the explicit ref
and ref mut
keywords are no longer required.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With