TL; DR:を代わりに使用&str
し&[T]
たり&T
、より一般的なコードを許可したりできます。
a String
またはa を使用する主な理由の1つは、Vec
容量を増減できるからです。ただし、不変の参照を受け入れる場合、Vec
またはでこれらの興味深いメソッドを使用することはできませんString
。
受け入れる&String
、&Vec
または&Box
もすることは必要で関数を呼び出すことができます前に、ヒープ上に割り当てられる引数を。aを受け入れると&str
、文字列リテラル(プログラムデータに保存)が許可され、&[T]
またはを受け入れると&T
、スタックに割り当てられた配列または変数が許可されます。不要な割り当てはパフォーマンスの低下です。これは通常、テストまたはメソッドでこれらのメソッドを呼び出そうとするとすぐに公開されますmain
。
awesome_greeting(&String::from("Anna"));
total_price(&vec![42, 13, 1337])
is_even(&Box::new(42))
もう1つのパフォーマンスの考慮事項は、&String
で&Vec
あり&Box
、を逆参照して&String
を取得しString
、2番目の逆参照を実行して最終的にになるため、不必要な間接層を導入し&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
}
これで、これらのメソッドをより幅広いタイプのセットで呼び出すことができます。たとえばawesome_greeting
、文字列リテラル("Anna"
)または割り当てられたを使用して呼び出すことができますString
。total_price
配列(&[1, 2, 3]
)または割り当てられたを参照して呼び出すことができますVec
。
追加またはから項目を削除したい場合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]
またはも受け入れることができます&mut str
。これにより、スライス内の特定の値を変更できますが、スライス内のアイテム数を変更することはできません(つまり、文字列に対して非常に制限されています)。
fn reset_first_price(prices: &mut [i32]) {
prices[0] = 0;
}
fn lowercase_first_ascii_character(s: &mut str) {
if let Some(f) = s.get_mut(0..1) {
f.make_ascii_lowercase();
}
}
&str
機能は制限されず、より一般的です(制限が少ないなど)」?また、ポイント3は多くの場合、それほど重要ではないと思います。通常、Vec
sとString
sはスタック上にあり、多くの場合、現在のスタックフレームの近くのどこかにさえ存在します。スタックは通常ホットで、逆参照はCPUキャッシュから提供されます。