She*_*ter 100 string reference rust borrowing
我写了一些Rust代码&String作为参数:
fn awesome_greeting(name: &String) {
println!("Wow, you are awesome, {}!", name);
}
Run Code Online (Sandbox Code Playgroud)
我还编写了代码来引用a Vec或Box:
fn total_price(prices: &Vec<i32>) -> i32 {
prices.iter().sum()
}
fn is_even(value: &Box<i32>) -> bool {
**value % 2 == 0
}
Run Code Online (Sandbox Code Playgroud)
但是,我收到一些反馈意见,这样做并不是一个好主意.为什么不?
She*_*ter 131
TL; DR:可以改为使用&str,&[T]也&T可以不丢失通用性.
使用a String或a的主要原因之一Vec是因为它们允许增加或减少容量.但是,当您接受不可变引用时,您不能在Vec或使用任何有趣的方法String.
接受&String,&Vec或者&Box 还需要一个配置,然后才能调用该方法.不必要的分配是性能损失.当您尝试在测试或方法中调用这些方法时,通常会立即显示此信息&str:
awesome_greeting(&String::from("Anna"));
Run Code Online (Sandbox Code Playgroud)
total_price(&vec![42, 13, 1337])
Run Code Online (Sandbox Code Playgroud)
is_even(&Box::new(42))
Run Code Online (Sandbox Code Playgroud)另一个性能考虑因素是&[T],&T并main引入一个不必要的间接层,因为你已经取消引用&String,得到一个&Vec,然后第二个引用结束&Box.
相反,您应该接受字符串slice(&String),slice(String)或仅引用(&str).甲&str,&[T]或&T将被自动强制转换为&String,&Vec<T>或&Box<T>分别.
fn awesome_greeting(name: &str) {
println!("Wow, you are awesome, {}!", name);
}
Run Code Online (Sandbox Code Playgroud)
fn total_price(prices: &[i32]) -> i32 {
prices.iter().sum()
}
Run Code Online (Sandbox Code Playgroud)
fn is_even(value: &i32) -> bool {
*value % 2 == 0
}
Run Code Online (Sandbox Code Playgroud)
现在,您可以使用更广泛的类型集来调用这些方法.例如,&str可以使用字符串literal(&[T])或已分配来调用&T.awesome_greeting可以通过引用array("Anna")或已分配来调用String.
如果你想添加或删除项目total_price或者&[1, 2, 3],你可以采取一个可变的引用(Vec或String):
fn add_greeting_target(greeting: &mut String) {
greeting.push_str("world!");
}
Run Code Online (Sandbox Code Playgroud)
fn add_candy_prices(prices: &mut Vec<i32>) {
prices.push(5);
prices.push(25);
}
Run Code Online (Sandbox Code Playgroud)
特别是对于切片,您也可以接受Vec<T>或&mut String.这允许您改变切片内的特定值,但是您无法更改切片内的项目数(这意味着它对字符串非常有限):
fn reset_first_price(prices: &mut [i32]) {
prices[0] = 0;
}
Run Code Online (Sandbox Code Playgroud)
fn lowercase_first_ascii_character(s: &mut str) {
if let Some(f) = s.get_mut(0..1) {
f.make_ascii_lowercase();
}
}
Run Code Online (Sandbox Code Playgroud)
Pet*_*all 18
除了Shepmaster的回答之外,接受a &str(以及类似的&[T]等)的另一个原因是因为除了 所有其他类型String并且&str也满足Deref<Target = str>.其中一个最值得注意的例子是Cow<str>,它让您可以非常灵活地处理自有或借用的数据.
如果你有:
fn awesome_greeting(name: &String) {
println!("Wow, you are awesome, {}!", name);
}
Run Code Online (Sandbox Code Playgroud)
但你需要用a调用它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());
Run Code Online (Sandbox Code Playgroud)
当您将参数类型更改为时&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);
Run Code Online (Sandbox Code Playgroud)
接受&str使得调用您的功能更加统一和方便,而"最简单"的方式现在也是最有效的.这些例子也适用于Cow<[T]>等.
| 归档时间: |
|
| 查看次数: |
5549 次 |
| 最近记录: |