TL; DR:可以改用&str
,&[T]
或&T
允许使用更通用的代码。
使用a String
或a的主要原因之一Vec
是因为它们允许增加或减少容量。但是,当您接受不可变的引用时,就不能在Vec
或上使用任何这些有趣的方法String
。
接受&String
,&Vec
或&Box
还需要在堆上进行分配后,才能调用函数的参数。接受a &str
允许字符串文字(保存在程序数据中),接受&[T]
或&T
允许堆栈分配的数组或变量。不必要的分配是性能损失。当您尝试在测试或方法中调用以下方法时,通常会立即暴露此信息main
:
awesome_greeting(&String::from("Anna"));
total_price(&vec![42, 13, 1337])
is_even(&Box::new(42))
另一个性能考虑因素是&String
,&Vec
并&Box
引入了不必要的间接层,因为您必须取消引用&String
以获得a String
,然后执行第二次取消以最终到达&str
。
相反,您应该接受字符串slice(&str
),slice(&[T]
)或仅引用(&T
)。甲&String
,&Vec<T>
或&Box<T>
将被自动强制转换为&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();
}
}
&str
更通用(例如:施加更少的限制)而不降低功能”之类的东西?另外:我认为第3点通常并不那么重要。通常Vec
s和String
s将存在于堆栈中,甚至经常位于当前堆栈帧附近。堆栈通常很热,并且将从CPU缓存中进行取消引用。