The original title: Daily Rust: Slice Patterns links: the original adventures.michaelfbryan.com/posts/daily… Praying for Rust
A nice little feature introduced in Rust 1.26, Basic Slice Patterns, enables pattern matching on slices of known length. Later in Rust 1.42, this feature was extended to use.. To match “everything else.”
This may seem like a small addition in terms of features, but it allows developers to write more expressive code.
remind
The code in this article can be found in the corresponding playground link. The code can be obtained and modified freely. If you think this article is good, or find any bugs in this article, please let me know in the issue Tracker of this blog.
Dealing with diversity
One of the simplest applications of slice pattern is to provide user-friendly information by matching fixed-length slices.
In general, it is good to be able to customize a language based on zero, one or more words in a sentence, as in the following example:
fn print_words(sentence: &str) {
let words: Vec<_> = sentence.split_whitespace().collect();
match words.as_slice() {
[] => println!("There were no words"),
[word] => println!("Found 1 word: {}", word),
_ => println!("Found {} words: {:? }", words.len(), words),
}
}
fn main() {
print_words("");
print_words("Hello");
print_words("Hello World!");
}
Copy the code
Code link: playground
The above code will print the following:
There were no words
Found 1 word: Hello
Found 2 words: ["Hello", "World!"]
Copy the code
Matches the beginning of a slice
. Known as the “rest” pattern, it lets you match the rest of the slice.
According to [] the ELF format (en.wikipedia.org/wiki/Execut… ELF, from which we can implement our IS_ELF () ‘function using rest mode.
use std::error::Error;
fn is_elf(binary: &[u8]) -> bool {
match binary {
[0x7f.b'E'.b'L'.b'F'. ] = >true, _ = >false,}}fn main() - >Result< (),Box<dyn Error>> {
letcurrent_exe = std::env::current_exe()? ;letbinary = std::fs::read(¤t_exe)? ;if is_elf(&binary) {
print!("{} is an ELF binary", current_exe.display());
} else {
print!("{} is NOT an ELF binary", current_exe.display());
}
Ok(())}Copy the code
Code link: playground
Checking for Palindromes
A common problem in getting started with programming is detecting palindromes. We know that the @ symbol will bind a new variable to all its matches, so we can match at the head and tail of the slice to implement a more elegant is_palindrome() function.
fn is_palindrome(items: &[char]) -> bool {
match items {
[first, middle @ .., last] => first == last && is_palindrome(middle),
[] | [_] => true,}}Copy the code
Code link: playground
A crude parameter parser
You may also want to “peeling off” the desired prefixes and suffixes in peeling mode.
Although more powerful Crate models like Clap and structopt already exist, we use slice mode to implement our own parameter parser.
fn parse_args(mut args: &[&str]) -> Args {
let mut input = String::from("input.txt");
let mut count = 0;
loop {
match args {
["-h" | "--help". ] => { eprintln! ("Usage: main [--input <filename>] [--count <count>] <args>...");
std::process::exit(1);
}
["-i" | "--input", filename, rest @ .. ] => { input = filename.to_string(); args = rest; } ["-c" | "--count", c, rest @ .. ] => { count = c.parse().unwrap(); args = rest; } [..] = >break,}}let positional_args = args.iter().map(|s| s.to_string()).collect();
Args {
input,
count,
positional_args,
}
}
struct Args {
input: String,
count: usize,
positional_args: Vec<String>,}Copy the code
Code link: playground
Irrefutable pattern matching
Although this is not a technical part of the slicing pattern feature, you can still use pattern matching to deconstruct fixed-length arrays in addition to match and iflet states. This is a great way to avoid fussiness by indexing sequences that are always valid.
fn format_coordinates([x, y]: [f32; 2]) -> String {
format!("{} | {}", x, y)
}
fn main() {
let point = [3.14, -42.0];
println!("{}", format_coordinates(point));
let [x, y] = point;
println!("x: {}, y: {}", x, y);
// Much more ergonomic than writing this!
// let x = point[0];
// let y = point[1];
}
Copy the code
Code link: playground
conclusion
For many of the features in Rust, slicing patterns are not very complex when used properly, and they can significantly improve the expressiveness of code.