为什么不鼓励接受对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]而不丧失通用性。


  1. 使用StringVec主要原因之一是允许增加或减less容量。 但是,当您接受不可变的引用时,您不能在VecString上使用任何有趣的方法。

  2. 在调用方法之前,接受&String&Vec需要分配。 不必要的分配是一个性能损失。 当您尝试在testing或main方法中调用这些方法时,通常会立即将其暴露出来:

     awesome_greeting(&String::from("Anna")); 
     total_price(&vec![42, 13, 1337]) 
  3. 另一个性能方面的考虑是&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


如果您想添加或删除StringVec<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; }