TL;DR:可以改用&str、&[T] 或&T 来允许更通用的代码。
-
使用String 或Vec 的主要原因之一是它们允许增加或减少容量。但是,当您接受不可变引用时,您不能在 Vec 或 String 上使用任何这些有趣的方法。
-
接受&String、&Vec 或&Box 还需要在调用函数之前将参数分配到堆上。接受&str 允许字符串文字(保存在程序数据中),接受&[T] 或&T 允许堆栈分配数组或变量。不必要的分配是性能损失。当您尝试在测试中调用这些方法或 main 方法时,这通常会立即暴露:
awesome_greeting(&String::from("Anna"));
total_price(&vec![42, 13, 1337])
is_even(&Box::new(42))
-
另一个性能考虑因素是 &String、&Vec 和 &Box 引入了不必要的间接层,因为您必须取消引用 &String 以获取 String,然后执行第二次取消引用以结束&str.
相反,您应该接受一个字符串切片 (&str)、一个切片 (&[T]),或者只是一个引用(&T)。 &String、&Vec<T> 或 &Box<T> 将被自动强制(通过 deref coercion)分别为 &str、&[T] 或 &T。
fn awesome_greeting(name: &str) {
println!("Wow, you are awesome, {}!", name);
}
fn total_price(prices: &[i32]) -> i32 {
prices.iter().sum()
}
fn is_even(value: &i32) -> bool {
*value % 2 == 0
}
现在您可以使用更广泛的类型集来调用这些方法。例如,awesome_greeting 可以用字符串字面量 ("Anna") 或 分配的 String 调用。 total_price 可以通过引用数组 (&[1, 2, 3]) 或分配的 Vec 来调用。
如果您想在String 或Vec<T> 中添加或删除项目,您可以采用可变引用(&mut String 或&mut Vec<T>):
fn add_greeting_target(greeting: &mut String) {
greeting.push_str("world!");
}
fn add_candy_prices(prices: &mut Vec<i32>) {
prices.push(5);
prices.push(25);
}
对于切片,您还可以接受&mut [T] 或&mut str。这允许您改变切片内的特定值,但您不能更改切片内的项目数(这意味着它对字符串非常有限):
fn reset_first_price(prices: &mut [i32]) {
prices[0] = 0;
}
fn lowercase_first_ascii_character(s: &mut str) {
if let Some(f) = s.get_mut(0..1) {
f.make_ascii_lowercase();
}
}