我写了一些以&String
为参数的Rust代码:
fn awesome_greeting(name: &String) {
println!("Wow, you are awesome, {}!", name);
}
我还编写了引用Vec
或Box
的代码:
fn total_price(prices: &Vec<i32>) -> i32 {
prices.iter().sum()
}
fn is_even(value: &Box<i32>) -> bool {
**value % 2 == 0
}
然而,我收到一些反馈意见,这样做并不是一个好主意。为什么不呢?
答案 0 :(得分:110)
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
才能获得{{ 1}}然后是第二个取消引用,以String
结束。
相反,您应该接受字符串切片(&str
),切片(&str
),或仅接受参考({{ 1}})。 &[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
或{{1 }}):
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]
答案 1 :(得分:13)
除了Shepmaster's answer之外,接受&str
(和类似的&[T]
等)的另一个原因是,除以外 {{ 1}}和String
也满足&str
。最著名的例子之一是Deref<Target = str>
,它使您可以灵活地处理自己拥有的数据还是借来的数据。
如果您有:
Cow<str>
但是您需要用fn awesome_greeting(name: &String) {
println!("Wow, you are awesome, {}!", name);
}
来调用它,您必须这样做:
Cow<str>
将参数类型更改为let c: Cow<str> = Cow::from("hello");
// Allocate an owned String from a str reference and then makes a reference to it anyway!
awesome_greeting(&c.to_string());
时,可以无缝使用&str
,而无需进行任何不必要的分配,就像Cow
一样:
String
接受let c: Cow<str> = Cow::from("hello");
// Just pass the same reference along
awesome_greeting(&c);
let c: Cow<str> = Cow::from(String::from("hello"));
// Pass a reference to the owned string that you already have
awesome_greeting(&c);
使调用您的函数更加统一和方便,并且“最简单”的方式现在也是最有效的。这些示例也可以与&str
等一起使用。