为什么不鼓励接受对String(&String)或Vec(&Vec)作为函数参数的引用?
我写了一些将&String
作为参数的Rust代码:
fn awesome_greeting(name: &String) { println!("Wow, you are awesome, {}!", name); }
我也写了代码,参考一个Vec
:
fn total_price(prices: &Vec<i32>) -> i32 { prices.iter().sum() }
不过,我收到一些反馈,这样做不是一个好主意。 为什么不?
TL; DR:可以改为使用&str
或&[T]
而不丧失通用性。
-
使用
String
或Vec
主要原因之一是允许增加或减less容量。 但是,当您接受不可变的引用时,您不能在Vec
或String
上使用任何有趣的方法。 -
在调用方法之前,接受
&String
或&Vec
也需要分配。 不必要的分配是一个性能损失。 当您尝试在testing或main
方法中调用这些方法时,通常会立即将其暴露出来:awesome_greeting(&String::from("Anna"));
total_price(&vec![42, 13, 1337])
-
另一个性能方面的考虑是
&String
或&Vec
引入了一个不必要的间接层,因为你已经取消了&String
来获得一个String
,然后第二个取消引用最终在&str
。
相反,你应该接受一个string切片 ( &str
)或一个切片 ( &[T]
)。 一个&String
或一个&Vec<T>
将被自动强制为一个&str
或一个&[T]
。
fn awesome_greeting(name: &str) { println!("Wow, you are awesome, {}!", name); }
fn total_price(prices: &[i32]) -> i32 { prices.iter().sum() }
现在你可以用更广泛的types来调用这些方法。 例如, awesome_greeting
可以用string文字( "Anna"
) 或分配的String
来调用。 可以通过引用数组( &[1, 2, 3]
) 或分配的Vec
来调用total_price
。
如果您想添加或删除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]
。 这允许您在切片中改变特定的值,但不能更改切片内的项目数量:
fn reset_first_price(prices: &mut [i32]) { prices[0] = 0; }