2016-10-12 54 views
45

我寫了一些鐵鏽代碼,需要&String作爲參數:爲什麼不鼓勵接受對String(&String),Vec(&Vec)或Box(&Box)作爲函數參數的引用?

fn awesome_greeting(name: &String) { 
    println!("Wow, you are awesome, {}!", name); 
} 

我也寫代碼,需要在參照VecBox

fn total_price(prices: &Vec<i32>) -> i32 { 
    prices.iter().sum() 
} 

fn is_even(value: &Box<i32>) -> bool { 
    **value % 2 == 0 
} 

不過,我收到一些反饋,這樣做並不是一個好主意。爲什麼不?

回答

59

TL; DR:可以改爲使用&str,&[T]&T而不喪失通用性。


  1. 一個使用StringVec的主要原因是因爲它們允許增加或減少容量。但是,如果您接受不可變引用,則不能在VecString上使用任何有趣的方法。

  2. 接受&String&Vec&Box需要分配,然後才能調用該方法。不必要的分配是性能損失。這通常是暴露時,馬上你嘗試調用在測試這些方法或main方法:

    awesome_greeting(&String::from("Anna")); 
    
    total_price(&vec![42, 13, 1337]) 
    
    is_even(&Box::new(42)) 
    
  3. 另一個性能考慮是&String&Vec&Box介紹一個不必要的間接層,因爲您已取消&String以獲得String,然後第二個解除引用最終在&str

相反,你應該接受串片&str),一個&[T]),或只是一個參考&T。 A &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 
} 

現在你可以調用這些方法與更廣泛的類型。例如,可以用字符串文字("Anna"分配String來調用awesome_greeting。可以調用total_price參考數組(&[1, 2, 3]分配Vec


如果你想添加或移除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; 
} 
+3

在開始時如何開始** tl; dr **?這個答案已經有些長了。像''&str'這樣的東西更普遍(如:限制較少)而沒有降低功能「?另外:第3點通常不是我認爲的那麼重要。通常'Vec's和'String's會在堆棧中生存,並且通常甚至會在當前堆棧框架附近。堆棧通常很熱並且取消引用將從CPU緩存中提供。 –

+2

@Shepmaster:關於分配成本,當談論強制分配時,可能值得提到子串/片的特定問題。 'total_price(&prices [0..4])'不需要爲該片分配一個新的向量。 –

相關問題