I'm implementing a parser in Rust and whitespace is a common pattern that I want to reuse in match
patterns.
This code works:
let ch = ' ';
match ch {
' ' | '\n' | '\t' | '\r' => println!("whitespace"),
_ => println!("token"),
}
This would get really repetitive if I need to keep on specifying the whitespace pattern each time. I would like to define that once and reuse it. I want to do something like:
let whitespace = ' ' | '\n' | '\t' | '\r';
let ch = ' ';
match ch {
whitespace => println!("whitespace"),
_ => println!("token"),
}
The compiler does not like the ws
assignment. It interprets the |
as a binary operation instead of alternation.
Can patterns be stored in variables somehow? Is there a better or more idiomatic way to do this?
Patterns are a special syntax in Rust for matching against the structure of types, both complex and simple. Using patterns in conjunction with match expressions and other constructs gives you more control over a program's control flow.
TLDR: in Rust, to match over type, we create a trait, implement a function for each type and call it on the element to match. Surround it with backticks to mark it as code. Single backticks for inline code, triple backticks for code blocks.
Rust has an extremely powerful control flow construct called match that allows you to compare a value against a series of patterns and then execute code based on which pattern matches.
Can patterns be stored in variables somehow?
No. Patterns are a compile-time construct, and variables hold run-time concepts.
Is there a better or more idiomatic way to do this?
Creating a function or method is always a good solution to avoid repeating code. You can then use this as a guard clause:
fn is_whitespace(c: char) -> bool {
match c {
' ' | '\n' | '\t' | '\r' => true,
_ => false,
}
}
fn main() {
let ch = ' ';
match ch {
x if is_whitespace(x) => println!("whitespace"),
_ => println!("token"),
}
}
I'd also strongly recommend using an existing parser, of which there are a multitude, but everyone wants their Rust "hello world" to be parsing, for whatever reason.
A parsing library I use allows writing code akin to this, where whitespace
is a function that knows how to parse the valid types of whitespace:
sequence!(pm, pt, {
_ = literal("if");
ws = whitespace;
_ = literal("let");
ws = append_whitespace(ws);
pattern = pattern;
ws = optional_whitespace(ws);
_ = literal("=");
ws = optional_whitespace(ws);
expression = expression;
}, |_, _| /* do something with pieces */);
Each of the things on the right-hand side are still individual functions that know how to parse something specific.
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