TL; DR: si può invece utilizzare &str
, &[T]
o &T
per consentire un codice più generico.
Uno dei motivi principali per utilizzare a String
o a Vec
è perché consentono di aumentare o diminuire la capacità. Tuttavia, quando si accetta un riferimento immutabile, non è possibile utilizzare nessuno di questi metodi interessanti su Vec
o String
.
L'accettazione di un &String
, &Vec
o richiede&Box
anche l'allocazione dell'argomento nell'heap prima di poter chiamare la funzione. L'accettazione di a consente una stringa letterale (salvata nei dati del programma) e l'accettazione di o consente un array o una variabile allocati nello stack. L'allocazione non necessaria è una perdita di prestazioni. Questo di solito viene esposto immediatamente quando provi a chiamare questi metodi in un test o in un metodo:&str
&[T]
&T
main
awesome_greeting(&String::from("Anna"));
total_price(&vec![42, 13, 1337])
is_even(&Box::new(42))
Un'altra considerazione sulle prestazioni è quella &String
, &Vec
e &Box
introdurre un livello di riferimento indiretto non necessario in quanto devi dereferenziare &String
per ottenere un String
e quindi eseguire un secondo dereferenziamento in cui finire &str
.
Invece, dovresti accettare una stringa slice ( &str
), slice ( &[T]
) o solo un riferimento ( &T
). A &String
, &Vec<T>
o &Box<T>
verrà automaticamente costretto a &str
, &[T]
o &T
, rispettivamente.
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
}
Ora puoi chiamare questi metodi con un insieme più ampio di tipi. Ad esempio, awesome_greeting
può essere chiamato con una stringa letterale ( "Anna"
) o allocata String
. total_price
può essere chiamato con un riferimento a un array ( &[1, 2, 3]
) o un allocato Vec
.
Se desideri aggiungere o rimuovere elementi da String
o Vec<T>
, puoi prendere un riferimento modificabile ( &mut String
o &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);
}
In particolare per le sezioni, puoi anche accettare un &mut [T]
o &mut str
. Ciò consente di modificare un valore specifico all'interno della sezione, ma non è possibile modificare il numero di elementi all'interno della sezione (il che significa che è molto limitato per le stringhe):
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
è più generale (come in: impone meno restrizioni) senza capacità ridotte"? Inoltre: il punto 3 spesso non è così importante credo. Di solitoVec
s eString
s vivranno nello stack e spesso anche da qualche parte vicino allo stack frame corrente. Lo stack è solitamente caldo e il dereferenziamento sarà servito da una cache della CPU.