TL; DR: замість того, щоб можна використовувати &str
, &[T]
або &T
для забезпечення більш загального коду.
Однією з головних причин використання a String
або a Vec
є те, що вони дозволяють збільшити або зменшити ємність. Однак, приймаючи незмінні посилання, ви не можете використовувати жоден із цих цікавих методів на Vec
або String
.
Прийом &String
, &Vec
або &Box
ж вимагає аргумент , щоб бути виділена в купі , перш ніж ви можете викликати функцію. Прийняття дозволу &str
дає рядковий літерал (збережений у програмі) та приймає &[T]
або &T
дозволяє масив або змінну, виділену стеком. Непотрібний розподіл - це втрата продуктивності. Зазвичай це виявляється відразу, коли ви намагаєтеся викликати ці методи в тесті або main
методі:
awesome_greeting(&String::from("Anna"));
total_price(&vec![42, 13, 1337])
is_even(&Box::new(42))
Ще один розгляд продуктивності полягає в тому &String
, що &Vec
і &Box
введіть непотрібний шар непрямості, оскільки вам доведеться знеструмити значення, &String
щоб отримати а, String
а потім виконати другий відвід, щоб закінчитися в &str
.
Натомість слід прийняти рядковий фрагмент ( &str
), фрагмент ( &[T]
) або просто посилання ( &T
). A &String
, &Vec<T>
або &Box<T>
буде автоматично примусово до a &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.