I have a struct in which one of the fields is an enum, and when using a match statement there is a lot of repetition that feels avoidable.
Basically what I have now is
match self.foo // which is an enum, Foo {
Foo::Bar => something,
Foo::Bazz => something else,
_ => you get the point
}
I tried:
match self.foo {
Foo::{
Bar => something,
Bazz => something else,
}
}
but did not have the intended effect. Is it possible to not have to retype Foo:: every time or is it just something I need to live with?
You can use the use Foo::*; statement to bring all the variants of Foo into scope:
enum Foo {
Bar,
Bazz,
}
fn main() {
let foo = Foo::Bar;
use Foo::*;
match foo {
Bar => println!("something"),
Bazz => println!("something else"),
}
}
You can import the names of enum variants to use them directly:
use Foo::*;
match self.foo {
Bar => something,
Bazz => something else,
}
This is how None and Some work without needing Option:: before them.
Related
Is it possible to wild card the variants of an enum, while still caputing its associated data?
enum BAR {
BAR1,
BAR2,
}
enum BAZ {
BAZ1,
BAZ2,
BAZ3,
}
enum FOO {
FOO1(BAR, BAZ),
FOO2(BAR, BAZ),
FOO3(BAR, BAZ),
//...
}
impl FOO {
pub fn getBar(&self) -> &BAR {
return match self {
FOO::FOO1(bar, _) => bar,
// _(bar, _) => bar,
}
}
}
The enum FOO has over 50 variants. The line FOO::FOO1(bar, _) => bar, does what I need, but it would be quite ugly to list all 50 variants, where all arms essentially look the same. Is there some form of _(bar, _) => bar, where the variants are being wild carded but the associated data is still retrievable?
Is there some form of _(bar, _) => bar, where the variants are being wild carded but the associated data is still retrievable?
No. You can achieve this via a macro, that's about it.
But I've got to say I'm questioning your structure: if you have "over 50 variants" all with exactly the same associated data why is it not a structure with 3 fields?
struct Foo {
discriminant: Whatever,
bar: Baz,
baz: Baz,
}
This is exactly equivalent to what you have on your hands, except it's not a pain in the ass to access bar and baz.
I have an enum which is defined as follows:
enum MyEnum {
X(u32),
Y(Vec<MyEnum>),
Z(Vec<MyEnum>),
}
As you can see, the enum is nested and can have other enums of its type inside of it. I'm trying to perform a simple check: I want to check if any of the u32s is greater than 5.
I have thought about using recursion here as this seems like an inherently recursive problem but from my searches it was clear that rust doesn't support recursion or that it is not recommended that it is used. How would I go about solving this problem and performing the check?
You can make a method over your Enum, and recursively call it:
enum MyEnum {
X(u32),
Y(Vec<MyEnum>),
Z(Vec<MyEnum>),
}
impl MyEnum {
fn greater_than(&self, x: u32) -> bool {
match self {
Self::X(v) => v > &x,
Self::Y(v) | Self::Z(v) => v.iter().any(|y| y.greater_than(x)),
}
}
}
Playground
It is perfectly ok to use recursion in Rust, there is no particular problem about it.
In your case, you could write your check like this:
fn my_check(en: &MyEnum) -> bool {
match en {
MyEnum::X(n) => *n > 5,
MyEnum::Y(v) | MyEnum::Z(v) => v.iter().any(my_check),
}
}
Rust has a question mark operator than can be used like this:
fn make_foo() -> Option<Foo> { ... }
fn make_bar() -> Option<Bar> {
let foo = make_foo()?;
// ... Many lines of code using `foo` to compute data for `Bar::make` ...
Some(Bar::make(...))
}
But what if I want a function returning Bar rather than Option<Bar> (thus retuning Bar::new instead of None when make_foo() returns None)?
Of course, I could do
fn make_bar() -> Bar {
match make_foo() {
None => { Bar::new() }
Some(foo) => {
// ... Many lines of code using `foo` to compute data for `Bar::make` ...
Bar::make(...)
}
}
}
but this increases nesting level for the entire function, which I do not like. I would like to have a replacement for the ? operator.
So I came up with
fn make_bar() -> Bar {
let foo = match make_foo() {
None => { return Bar::new(); }
Some(v) => v
};
// ... Many lines of code using `foo` to compute data for `Bar::make` ...
Bar::make(...)
}
Is this idiomatic Rust? Or are there better solutions?
Is this idiomatic Rust?
Yes, it looks fine. You can remove the braces:
let foo = match make_foo() {
None => return Bar::new(),
Some(v) => v
};
The best will be let-else (unstable):
fn make_bar() -> Bar {
let Some(foo) = match make_foo() else {
return Bar::new();
};
// ... Many lines of code using `foo` to compute data for `Bar::make` ...
Bar::make(...)
}
For a similar one, see Idiomatic way to handle errors with an early return in Rust.
There's multiple ways to do this and I wouldn't necessarily say one is better than the other. However, let me give you one more option that may be useful if you could be using the ? operator multiple times in this function. Having many early return Bar::new() will likely get old. With this approach you can have your cake and eat it too.
Option has many utility methods. You can combine .and_then() with a final .unwrap_or_else() in this situation:
fn make_bar() -> Bar {
make_foo()
.and_then(|foo| {
// Do stuff with foo
Some(Bar::make(...))
})
.unwrap_or_else(Bar::new)
}
This does increase the nesting level, but only once, and has the advantage that you can use ? inside of the mapping function to cause the outer function to return the default Bar::new() value.
(If you implement Default on Bar then you could even use the less-verbose .unwrap_or_default() at the end.)
I have some non-copyable type and a function that consumes and (maybe) produces it:
type Foo = Vec<u8>;
fn quux(_: Foo) -> Option<Foo> {
Some(Vec::new())
}
Now consider a type that is somehow conceptually very similar to Box:
struct NotBox<T> {
contents: T
}
We can write a function that temporarily moves out contents of the NotBox and puts something back in before returning it:
fn bar(mut notbox: NotBox<Foo>) -> Option<NotBox<Foo>> {
let foo = notbox.contents; // now `notbox` is "empty"
match quux(foo) {
Some(new_foo) => {
notbox.contents = new_foo; // we put something back in
Some(notbox)
}
None => None
}
}
I want to write an analogous function that works with Boxes but the compiler does not like it:
fn baz(mut abox: Box<Foo>) -> Option<Box<Foo>> {
let foo = *abox; // now `abox` is "empty"
match quux(foo) {
Some(new_foo) => {
*abox = new_foo; // error: use of moved value: `abox`
Some(abox)
}
None => None
}
}
I could return Some(Box::new(new_foo)) instead but that performs unnecessary allocation - I already have some memory at my disposal! Is it possible to avoid that?
I would also like to get rid of the match statements but again the compiler is not happy with it (even for the NotBox version):
fn bar(mut notbox: NotBox<Foo>) -> Option<NotBox<Foo>> {
let foo = notbox.contents;
quux(foo).map(|new_foo| {
notbox.contents = new_foo; // error: capture of partially moved value: `notbox`
notbox
})
}
Is it possible to work around that?
So, moving out of a Box is a special case... now what?
The std::mem module presents a number of safe functions to move values around, without poking holes (!) into the memory safety of Rust. Of interest here are swap and replace:
pub fn replace<T>(dest: &mut T, src: T) -> T
Which we can use like so:
fn baz(mut abox: Box<Foo>) -> Option<Box<Foo>> {
let foo = std::mem::replace(&mut *abox, Foo::default());
match quux(foo) {
Some(new_foo) => {
*abox = new_foo;
Some(abox)
}
None => None
}
}
It also helps in the map case, because it does not borrow the Box:
fn baz(mut abox: Box<Foo>) -> Option<Box<Foo>> {
let foo = std::mem::replace(&mut *abox, Foo::default());
quux(foo).map(|new_foo| { *abox = new_foo; abox })
}
Moving out of boxes is special-cased in the compiler. You can move something out of them, but you can't move something back in, because the act of moving out also deallocates. You can do something silly with std::ptr::write, std::ptr::read, and std::ptr::replace, but it's hard to get it right, because something valid should be inside a Box when it is dropped. I would recommend just accepting the allocation, or switching to a Box<Option<Foo>> instead.
We can write a function that temporarily moves out contents of the NotBox and puts something back in before returning it
That's because you can partially move out from the struct that you take by value. It behaves as if all fields were separate variables. That is not possible though if the struct implements Drop, because drop needs the whole struct to be valid, always (in case of panic).
As for providing workaround, you haven't provided enough information – especially, why baz needs to take Box as an argument and why quux can't? Which functions are yours and which are part of an API you can't change? What is the real type of Foo? Is it big?
The best workaround would be not to use Box at all.
I have an enum:
pub enum Enum1 {
A(String),
B(i64),
C(f64)
}
How can I do pattern matching against A? That is, I want to get its String value. I've tried this:
match optionMyEnum {
Some(A(x: String)) => ...
and got plenty of the compile errors.
The Rust Programming Language has an entire section on matching. I'd highly encourage you to read that section (and the entire book). A lot of time and effort has gone into that documentation.
You simply specify a name to bind against. There's no need to write out types:
pub enum Enum {
A(String),
B(i64),
C(f64),
}
fn main() {
let val = Enum::A("hello".to_string());
match val {
Enum::A(x) => println!("{}", x),
_ => println!("other"),
}
}
In many cases, you will want to bind to a reference to the values:
Enum::A(ref x) => println!("{}", x),