What does { .. } mean in a pattern? - syntax

I found the following piece of code in the doc about actix:
#[macro_use]
extern crate failure;
use actix_web::{error, http, HttpResponse};
#[derive(Fail, Debug)]
enum UserError {
#[fail(display = "Validation error on field: {}", field)]
ValidationError { field: String },
}
impl error::ResponseError for UserError {
fn error_response(&self) -> HttpResponse {
match *self {
UserError::ValidationError { .. } =>
HttpResponse::new(http::StatusCode::BAD_REQUEST),
}
}
}
What does { .. } mean here?

It's a pattern-matching destructuring wildcard that allows one to not need to specify all the members of an object. In this case:
UserError::ValidationError { .. }
It is enough for that match branch that the enum variant is ValidationError, regardless of its contents (in this case field):
enum UserError {
#[fail(display = "Validation error on field: {}", field)]
ValidationError { field: String },
}
It is also useful when one is concerned only with some members of an object; consider a Foo struct containing baz and bar fields:
struct Foo {
bar: usize,
baz: usize,
}
If you were only interested in baz, you could write:
fn main() {
let x = Foo { bar: 0, baz: 1 };
match x {
Foo { baz, .. } => println!("{}", baz), // prints 1
_ => (),
}
}

Related

How to read a value of an enum which associates with a custom type in Rust?

I have an implementation in Rust as follows. In the main function, I am reading a value in SalaryRange enum and this will display High("So High").
// This can be a complex type, just using string for the question
type SRange = String;
type SalEnu = SalaryRange<SRange>;
struct User<SRange> {
username: String,
email: String,
sign_in_count: u64,
active: bool,
income: Income<SRange>,
}
struct Income<SRange> {
salary_range: SalaryRange<SRange>
}
#[derive(Debug)]
enum SalaryRange<SRange> {
Low(SRange),
Mid(SRange),
High(SRange),
}
fn main() {
let user1 = User {
email: String::from("test#email.com"),
username: String::from("test_name"),
active: true,
sign_in_count: 1,
income: Income {
salary_range: (
SalaryRange::High("So High")
)
},
};
let mut srange: SalaryRange<&str> = user1.income.salary_range;
println!("{:?}", srange);
}
Link for this example can be found here.
Just wanted to know if there is a possibility to read and print the value in that enum as println!("{:?}", srange::High);, just to print out the string value?
I only want to print the value So High.
If I use srange::High This will throw an error saying
println!("{:?}", srange::High);
| ^^^^^^ use of undeclared type or module `srange`
error: aborting due to previous error
You can implement a method on your enum to extract the value:
#[derive(Debug)]
enum SalaryRange<S> {
Low(S),
Mid(S),
High(S),
}
impl<S> SalaryRange<S> {
fn value(&self) -> &S {
match self {
SalaryRange::Low(value) => value,
SalaryRange::Mid(value) => value,
SalaryRange::High(value) => value,
}
}
}
println!("{:?}", srange.value());
You can pattern match srange with the if let syntax.
if let SalaryRange::High(s) = srange {
println!("{}", s);
}
will print "so high".
I know it's been a while since the question has been opened, but I would like to complete Peter's answer.
There is a more idiomatic way to achieve what you want. Just implement the std::fmt::Display trait to your enum as following:
pub enum SalaryRange {
LOW(String),
MID(String),
HIGH(String),
}
impl std::fmt::Display for SalaryRange {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let content = match self {
SalaryRange::LOW(content) => content,
SalaryRange::MID(content) => content,
SalaryRange::HIGH(content) => content,
};
write!(f, "{}", content)
}
}
The std::fmt::Display trait allows you to display the content held by your enum value like this:
let salary_range = SalaryRange::HIGH("So high".to_string());
println!("{}", salary_range);
// outputs: "So high"
This should work with any type.
Playground to test it: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=eaea33a955dc9dcd81a4b96ec22d82bd

How to get access to enum variant unnamed field?

I would like to print data of tuple enum without named fields.
A tuple is a general way of grouping together some number of other values with a variety of types into one compound type.
#[derive(Debug)]
enum Coin {
Penny(String),
Nickel { id: String },
}
fn main() {
let penny = Coin::Penny(String::from("penny"));
let nickel: Coin = Coin::Nickel { id: String::from("nickel") };
println!("{} {:?} ", penny.0, penny);
println!("{:?}", nickel);
}
In this example, Nickel is a struct-like enum variant, whereas Penny is simply called an enum variant.
I get a compiler error:
error[E0609]: no field `0` on type `Coin`
For more information about this error, try `rustc --explain E0609`.
You can use a match statement or alternatively an if let statement to use the variant's associated value:
#[derive(Debug)]
enum Coin {
Penny(String),
Nickel { id: String },
}
fn main() {
let penny = Coin::Penny(String::from("penny"));
let nickel: Coin = Coin::Nickel {
id: String::from("nickel"),
};
if let Coin::Penny(name) = penny {
println!("{}", name);
}
if let Coin::Nickel{ id } = nickel {
println!("{}", id);
}
}
Playground link
Example using match statement:
#[derive(Debug)]
enum Coin {
Penny(String),
Nickel { id: String },
}
fn main() {
let penny = Coin::Penny(String::from("penny"));
let nickel: Coin = Coin::Nickel {
id: String::from("nickel"),
};
match &penny {
Coin::Penny(id) => {
println!("{}; {:?}", id, penny);
}
_ => {}
}
match &nickel {
Coin::Nickel { id } => {
println!("{}; {:?}", id, nickel);
}
_ => {}
}
}
Playground link

How do I conditionally check if an enum is one variant or another?

I have an enum with two variants:
enum DatabaseType {
Memory,
RocksDB,
}
What do I need in order to make a conditional if inside a function that checks if an argument is DatabaseType::Memory or DatabaseType::RocksDB?
fn initialize(datastore: DatabaseType) -> Result<V, E> {
if /* Memory */ {
//..........
} else if /* RocksDB */ {
//..........
}
}
First have a look at the free, official Rust book The Rust Programming Language, specifically the chapter on enums.
match
fn initialize(datastore: DatabaseType) {
match datastore {
DatabaseType::Memory => {
// ...
}
DatabaseType::RocksDB => {
// ...
}
}
}
if let
fn initialize(datastore: DatabaseType) {
if let DatabaseType::Memory = datastore {
// ...
} else {
// ...
}
}
==
#[derive(PartialEq)]
enum DatabaseType {
Memory,
RocksDB,
}
fn initialize(datastore: DatabaseType) {
if DatabaseType::Memory == datastore {
// ...
} else {
// ...
}
}
matches!
This is available since Rust 1.42.0
fn initialize(datastore: DatabaseType) {
if matches!(datastore, DatabaseType::Memory) {
// ...
} else {
// ...
}
}
See also:
How to compare enum without pattern matching
Read from an enum without pattern matching
Compare enums only by variant, not value
https://doc.rust-lang.org/std/macro.matches.html
// A simple example that runs in rust 1.58:
enum Aap {
Noot(i32, char),
Mies(String, f64),
}
fn main() {
let aap: Aap = Aap::Noot(42, 'q');
let noot: Aap = Aap::Mies(String::from("noot"), 422.0);
println!("{}", doe(aap));
println!("{}", doe(noot));
}
fn doe(a: Aap) -> i32 {
match a {
Aap::Noot(i, _) => i,
Aap::Mies(_, f) => f as i32,
}
}

Why do I get an error when pattern matching a struct-like enum variant with fields?

I can't get rid of an error on this code:
#[derive(PartialEq, Copy, Clone)]
pub enum OperationMode {
ECB,
CBC { iv: [u8; 16] },
}
pub struct AES {
key: Vec<u8>,
nr: u8,
mode: OperationMode,
}
impl AES {
pub fn decrypt(&mut self, input: &Vec<u8>) {
match self.mode {
OperationMode::ECB => {},
OperationMode::CBC(_) => {},
};
}
}
The pattern matching at the end of the decrypt function gives an error:
error[E0532]: expected tuple struct/variant, found struct variant `OperationMode::CBC`
--> src/main.rs:17:13
|
17 | OperationMode::CBC(_) => {},
| ^^^^^^^^^^^^^^^^^^ did you mean `OperationMode::CBC { /* fields */ }`?
It tells me to look at the output of rustc --explain E0532 for help, which I did.
They show this example of wrong code:
enum State {
Succeeded,
Failed(String),
}
fn print_on_failure(state: &State) {
match *state {
// error: expected unit struct/variant or constant, found tuple
// variant `State::Failed`
State::Failed => println!("Failed"),
_ => ()
}
}
In this example, the error occurs because State::Failed has a field which isn't matched. It should be State::Failed(ref msg).
In my case I'm matching the field of my enum because I'm doing OperationMode::CBC(_). Why does the error happen?
Enum variants have three possible syntaxes:
unit
enum A { One }
tuple
enum B { Two(u8, bool) }
struct
enum C { Three { a: f64, b: String } }
You have to use the same syntax when pattern matching as the syntax the variant was defined as:
unit
match something {
A::One => { /* Do something */ }
}
tuple
match something {
B::Two(x, y) => { /* Do something */ }
}
struct
match something {
C::Three { a: another_name, b } => { /* Do something */ }
}
Beyond that, you can use various patterns that allow ignoring a value, such as _ or ... In this case, you need curly braces and the .. catch-all:
OperationMode::CBC { .. } => { /* Do something */ }
See also:
Ignoring Values in a Pattern in The Rust Programming Language
Appendix B: Operators and Symbols in The Rust Programming Language
How to match struct fields in Rust?

Modifying a value inside an enum while matching

Is it possible to directly modify a value embedded inside an enum?
The following fails with error: cannot borrow immutable anonymous field `a.0` as mutable, even though I used ref mut.
enum Foo {
Bar(usize),
}
fn main() {
let a = Foo::Bar(10);
match a {
Foo::Bar(ref mut val) => *val = 33,
}
match a {
Foo::Bar(val) => println!("{}", val), // should print 33
}
}
That's not a huge problem because I can do the following as a work-around:
match a {
Foo::Bar(val) => a = Foo::Bar(33),
}
But is this the correct way?
You need to make the binding to a mutable.
enum Foo {
Bar(usize),
}
fn main() {
let mut a = Foo::Bar(10);
match a {
Foo::Bar(ref mut val) => *val = 33,
}
match a {
Foo::Bar(val) => println!("{}", val), // 33
}
}

Resources