改善 Rust 代碼的 6 個建議
一,if let
你可能已經編寫了一些匹配單個分支和一個 None 的代碼塊,以表示對其餘選項不做任何操作。例如,只在獲得 Some(foo)、Err(error) 或 Ok(bar) 時執行操作。對於這些情況,我們使用 if let。
fn overflow(n: i32, max: i32) -> Option<i32> {
if n > max {
Some(n - max)
} else {
None
}
}
fn main() {
let n = 15;
// instead of this
match overflow(n, 10) {
Some(overflow) => println!("The input value has gone {overflow} over the maximum"),
_ => {}
}
// do this
if let Some(overflow) = overflow(n, 10) {
println!("The input value has gone {overflow} over the maximum")
}
}
If let 展現了清晰的邏輯和節省了無用的代碼。
二,Result 別名處理錯誤
這取決於個人喜好,但在相同的文件或模塊中,聲明瞭相同的結果,但是有不同的錯誤,它非常有用。
enum ReadingError {
OutOfBounds,
InvalidBuffer
}
trait InsteadOfThis {
fn next_char() -> Result<u8, ReadingError>;
fn next_line() -> Result<String, ReadingError>;
fn char_at(pos: usize) -> Result<u8, ReadingError>;
}
// new result declaring the error just once
type ReadingResult<T> = Result<T, ReadingError>;
trait YouCanDoThis {
fn next_char() -> ReadingResult<u8>;
fn next_line() -> ReadingResult<String>;
fn char_at(pos: usize) -> ReadingResult<u8>;
}
fn get_first(buffer: &[u8]) -> ReadingResult<String> {
if buffer.len() > 0 {
Ok(buffer[0].to_string())
} else {
Err(ReadingError::OutOfBounds)
}
}
fn main() {
if let Ok(first) = get_first(&"foo".as_bytes()) {
println!("The first char is {}", first)
}
}
爲 result 創建新的別名,可以允許你使用 “默認錯誤”。
三,include_str! 和 include_bytes!
這兩個宏對於某些項目來說非常有用,特別是在基於文本輸入創建原型或製作小程序時。它們的使用非常簡單,它們讀取指定路徑中的文件,並在文件初始化時將內容保存在一個常量中。這將允許您不必硬編碼一些有問題的或大的字符串常量,甚至可以從版本控制中刪除它們。
const TOKEN_AS_STR: &'static str = include_str!("./token.txt");
const TOKEN_AS_BYTES: &[u8] = include_bytes!("./token.txt");
fn main() {
assert_eq!("HelLoWoRLd", TOKEN_AS_STR);
assert_eq!("HelLoWoRLd".as_bytes(), TOKEN_AS_BYTES);
}
四,使用 enumerate 獲取集合索引
enumerate 是來自 Iterator 特性的方法,在迭代器調用的末尾添加此方法將把每個循環的內容更改爲包含索引和值的元組。
fn main() {
let vec = vec!["f", "o", "o"];
// instead of this
for i in 0..vec.len() {
println!("The character at {i} is {}", vec[i]);
}
// you can use this
for (i, char) in vec.iter().enumerate() {
println!("The character at {i} is {char}");
}
}
它更清晰,甚至可以保存在 print 的參數中 (vec[i] 不能在字面值字符串中使用)。
五,Self
struct Foo {
bar: i32
}
impl Foo {
fn instead_of_this() -> Foo {
Foo { bar: 0 }
}
fn you_can_use_this() -> Self {
Self { bar: 0 }
}
}
fn main() {
let a = Foo::instead_of_this();
let b = Foo::you_can_use_this();
assert_eq!(a.bar, b.bar);
}
如果我把 Foo 改成 BetterName,我就不需要修改第二個方法了。
六,讀取 &[T] 而不是 & vec
很多時候,我們必須實現讀取元素集合的函數。在這種情況下,我們可以請求 &[T] 而不是借用向量。這將爲我們提供相同的功能 (如果我們只打算讀取),但具有更大的靈活性。
fn instead_of_this(chars: &Vec<u8>) -> Option<&u8> {
chars.iter().find(|&&x| x == b"\n"[0])
}
fn do_this(chars: &[u8]) -> Option<&u8> {
chars.iter().find(|&&x| x == b"\n"[0])
}
fn main() {
let vec: Vec<u8> = vec![77, 78, 2];
let arr: &[u8] = b"ab\n";
let str: &str = "ab\n";
let _ok = instead_of_this(&vec);
//let mismatched_types = instead_of_this(&arr);
//let mismatched_types = instead_of_this(str.as_bytes());
let _from_vec = do_this(&vec);
let _from_arr = do_this(arr);
let _from_str = do_this(str.as_bytes());
}
文翻譯自:
tps://betterprogramming.pub/rust-beginner-tips-8ecc2503517e
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/gJhjugyrAF90BYML4ZAObg