本文提炼于:
感谢作者以及出版社为广大 Rust 提供了一本这么好的 Rust 编码参考规则。
Rust isn’t a language where you’re going to be doing much in the way of converting between pointers and integers — 在 C / C++ 中是允许操作内存地址的,比如加减内存地址。
Rust 允许在数字字面量声明类型:
let x = 23i32;
Rust 的 char 字符,在内存中仍然保持为 4 字节 Unicode 值,而不是转换为 32 位整数。
在 Rust 中使用 try_into() 进行大位数的数字类型到小位数数字类型的转换,使用 into() 进行小位数到大位数的数字类型转换。
Arrays 用于聚合一个类型的多个实例。Tuple 用于聚合多个类型的多个实例,Structs 同样用于聚合多个类型的多个类型。但是允许通过名称来引用各个字段。
enum 允许携带一个数字或字符串值,并且具有类型安全检查。
使用 match 的时候建议添加 _ ⇒ {} 作为默认选项。
在 Rust 中,表达可能存在错误使用 Result<T, E>,表达可能不存在值使用 Option<T> 。
Method 方法,需要依附在 enum structs 等结构上,通常为 impl 结构体名称,在 fn 前使用 pub 表示该方法为公开方法,允许从 impl 块外的地方调用。
Rust 中呀很多很有意思的写法,根据匹配 enum 的值在一个 impl 的方法中以不同的方式进行计算,如下:
enum Shape {
Rectangle { width: f64, height: f64 },
Circle { radius: f64 },
}
impl Shape {
pub fn area(&self) -> f64 {
match self {
Shape::Rectangle { width, height } => width * height,
Shape::Circle { radius } => std::f64::consts::PI * radius * radius,
}
}
}
Rust 支持函数指针,允许将一整个函数赋值给一个变量。
Rust 支持闭包,即将函数作为另一个函数的参数进行传递,当然 lambda 表达式支持也少不了。Rust 的表达式语法为 |args…| = { … }; 。
对于 Rust 语言而言,这种基于语句(statement)和表达式(expression)的方式是非常重要的,你需要能明确的区分这两个概念, 但是对于很多其它语言而言,这两个往往无需区分。基于表达式是函数式语言的重要特征,表达式总要返回值。 — 圣经
可以使用一些 Trait 来对作为参数传入的函数类型作出限制。FnOnce 是指移交所有权的参数;FnMut 相当于 &mut T 指传入一个可变引用;Fn 相当于 &T,指传入引用。
pub fn modify_all<F>(data: &mut [u32], mut mutator: F)
where
F: FnMut(u32) -> u32,
{
for value in data {
*value = mutator(*value);
}
}
Rust 没有函数重载,函数重载有违 Rust 设计哲学之一的 Be Explicit,而大多数情况都可以改用泛型解决。
use num::Num;
fn plus<T: Num>(a: T, b: T) -> T {
a + b
}
Rust 可以依据 Trait 限制泛型边界(Trait bounds)。
pub fn dump_sorted<T>(mut collection: T)
where
T: Sort + IntoIterator,
T::Item: std::fmt::Debug,
{
// Next line requires `T: Sort` trait bound.
collection.sort();
// Next line requires `T: IntoIterator` trait bound.
for item in collection {
// Next line requires `T::Item : Debug` trait bound
println!("{:?}", item);
}
}
[Option<T>](https://doc.rust-lang.org/std/option/enum.Option.html): To express that a value (of typeT) may or may not be present[Result<T, E>](https://doc.rust-lang.org/std/result/enum.Result.html): For when an operation to return a value (of typeT) may not succeed and may instead return an error (of typeE)
正如前面所提:在 Rust 中,表达可能存在错误使用 Result<T, E>,表达可能不存在值使用 Option<T> 。
我们使用 match 来匹配 Option 和 Result:
// Option
struct S {
field: Option<i32>,
}
let s = S { field: Some(42) };
match &s.field {
Some(i) => println!("field is {i}"),
None => {}
}
// Result
let result = std::fs::File::open("/etc/passwd");
let f = match result {
Ok(f) => f,
Err(_e) => panic!("Failed to open /etc/passwd!"),
};
使用 if let 语句或是 if let else 语句简化 Option 和 Result 代码的解析
// Option
if let Some(i) = &s.field {
println!("field is {i}");
}
// Result
if let Ok(i) = &s.field {
println!("field is {i}");
}
应该处理或返回 Option 或 Result 而不是使用 unwarp 忽略封装直接返回结果。
However, in many situations, the right decision for error handling is to defer the decision to somebody else.
使用 unwarp 时候,如果遇到 None 或是 Err,将导致代码将在此处被 panic!,除非你清楚自己在干什么,否则不要使用它。
标记一个 #[must_use] 可以迫使使用者必须处理 Result。
warning: unused `Result` that must be used
--> src/main.rs:63:5
|
63 | f.set_len(0); // Truncate the file
| ^^^^^^^^^^^^
|
= note: this `Result` may be an `Err` variant, which should be handled
= note: `#[warn(unused_must_use)]` on by default
help: use `let _ = ...` to ignore the resulting value
|
63 | let _ = f.set_len(0); // Truncate the file
| +++++++
可以使用 ? 操作符 将错误向上传播。
• In particular, use these transformations to convert result types into a form where the
?operator applies.
pub fn find_user(username: &str) -> Result<UserId, std::io::Error> {
let f = std::fs::File::open("/etc/passwd")?;
// ...
}