Rust 技巧:AsRef-str- 和 Into-String-
Rustd 的字符串類型有兩種不同變體:&str 和 String。它們的不同之處在於 & str 是對 String 或 str 的引用,String 是動態分配的字符串對象。
use std::time::{SystemTime, UNIX_EPOCH};
fn time_stamp(msg: &str) -> String {
let time = SystemTime::now()
.duration_since(UNIX_EPOCH).unwrap().as_millis();
time.to_string() + ": " + msg
}
fn main() {
let s1 = "msg as &str";
let s2 = String::from("msg as String");
println!("{}", time_stamp(s1));
println!("{}", time_stamp(&s2)); // 注意額外的' & '字符
}
由於函數 time_stamp() 接受 & str 類型作爲形參,因此必須顯式地將 String 類型轉換爲帶有 & 字符的字符串,否則,我們將得到 Rust 編譯錯誤。如果 Rust 可以自動處理這兩種類型豈不是很好?這是可以的!不需要指定具體的參數類型 & str,我們可以指定一個實現 AsRef trait 的類型:
fn time_stamp(msg: impl AsRef<str>) -> String {
let time = SystemTime::now()
.duration_since(UNIX_EPOCH).unwrap().as_millis();
time.to_string() + ": " + msg.as_ref()
}
fn main() {
let s1 = "msg as &str";
let s2 = String::from("msg as String");
println!("{}", time_stamp(s1));
println!("{}", time_stamp(s2)); // 去掉了' & '字符
}
現在,我們可以將任何實現 AsRef 的類型傳遞給函數,比如 & str 或 String。這在爲庫設計 API 時特別有用,因爲它使客戶端代碼更容易編寫。
不過要注意,也不是在任何情況下都使用這個技巧。考慮下面的函數,你覺得有什麼問題嗎?
fn concat(msg1: impl AsRef<str>, msg2: impl AsRef<str>) -> String {
msg1.as_ref().to_owned() + "; " + msg2.as_ref()
}
當爲 msg1 提供的類型已經是一個 String 時,函數 concat 正在做不必要的工作,因爲它正在調用 msg1 上的 to_owned() 方法。理想情況下,如果 msg1 已經是 String 類型,我們希望重用它。爲此,你可以使用另一個 Into 的 trait:
fn concat(msg1: impl Into<String>, msg2: impl AsRef<str>) -> String {
msg1.into() + "; " + msg2.as_ref()
}
總之,如果首選類型是 & str,使用 AsRef trait 綁定,如果首選類型是 String,使用 Into trait 綁定。此外,只要注意不要像前面的例子那樣執行不必要的工作,就不會有性能損失!
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/W2LTSUVV12ETFDlJenv0ag