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
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
不过要注意,也不是在任何情况下都使用这个技巧。考虑下面的函数,你觉得有什么问题吗?
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
fn concat(msg1: impl Into<String>, msg2: impl AsRef<str>) -> String {
msg1.into() + "; " + msg2.as_ref()
}
总之,如果首选类型是&str,使用AsRef
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8