译者注:这是一篇结合切片和模式匹配的范例,它运用了 Rust Book: Patterns and Matching 篇章的知识。Rust 的类型系统和模式匹配相辅相成,呈现出简洁而强大、抽象而具体的表达力。
.. 语法匹配“其他所有东西”。.. 语法匹配看起来只是一个小小的补充,但它为开发人员提供了编写更具表现力的代码的机会。本文中编写的代码都附有 playground 链接。如果您发现这很有用或发现文章中的错误,请在博客的 issue 上告诉我!
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!");
}
There were no words
Found 1 word: Hello
Found 2 words: ["Hello", "World!"]
.. 语法称为 rest 模式,可让您匹配切片的其余部分。0x7f ELF。is_elf() 检查。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>> {
let current_exe = std::env::current_exe()?;
let binary = 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(())
}
译者注:英语里回文和中文的古诗词回文不同,palindromes 指“正反读都一样的词语”。具体例子见 知乎 。
@ 符号将匹配的任何内容绑定到一个新变量,运用在切片的开头和结尾进行匹配,来创建一个特别优雅的 is_palindrome() 函数。fn is_palindrome(items: &[char]) -> bool {
match items {
[first, middle @ .., last] => first == last && is_palindrome(middle),
[] | [_] => true,
}
}
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>,
}
match 或 if let 语句之外的固定数组。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];
}
译者注:如果你对 (ir)refutable 不熟悉,那么你应该仔细看看 Rust Book: refutability 部分。以下是我对 refutablity 的总结。
这个词直白地翻译叫做 “可反驳的”,而我倾向于使用“挂一漏万”来理解。
if let Some(x) = a_value 表达式中的 Some(x);如果变量 a_value 中的值是 None 而不是 Some,那么 Some(x) 模式不能匹配。if let 和 while let 表达式被限制为只能接受可反驳的模式,因为根据定义他们意在处理可能的失败:条件表达式的功能就是根据成功或失败执行不同的操作。match 匹配分支必须使用可反驳模式,除了最后一个分支需要使用能匹配任何剩余值的不可反驳模式。在可反驳模式的地方使用不可反驳模式的例子:
if let x = 5 {
println!("{}", x);
};
// 编译器警告:将不可反驳模式用于 `if let` 是没有意义的
warning: irrefutable if-let pattern
--> <anon>:2:5
|
2 | / if let x = 5 {
3 | | println!("{}", x);
4 | | };
| |_^
|
= note: #[warn(irrefutable_let_patterns)] on by default
这个词直白地翻译叫做 “不可反驳的”,而我倾向于使用“万无一失”来理解。
let x = 5; 语句中的 x,因为 x 可以匹配任何值所以不可能会失败。let 语句和 for 循环 只能接受不可反驳的模式,因为通过不匹配的值程序无法进行有意义的工作。在不可反驳模式的地方使用可反驳模式的例子:
let Some(x) = some_option_value;
// 编译器报错:
error[E0005]: refutable pattern in local binding: `None` not covered
-->
|
3 | let Some(x) = some_option_value;
| ^^^^^^^ pattern `None` not covered
some_option_value 的值是 None,其不会成功匹配模式 Some(x),表明这个模式是可反驳的。let 语句只能接受不可反驳模式因为代码不能通过 None 值进行有效的操作。Some(x) 的每一个可能的值, 所以 Rust 会合理地抗议。if let Some(x) = some_option_value {
println!("{}", x);
}
原文作者:Rust语言中文社区;如有侵权,请联系管理员删除。