Rust implementa un array di caratteri in due modi: str e String.
str, noto anche come «string slice», di solito si usa con un riferimento, cioè come &str.
Per capire perché, può aiutare capire perché la riga di codice seguente non viene compilata
const MY_CONST: str = *"Hello, World!";
// the size for values of type `str` cannot be known at compilation time
// the trait `Sized` is not implemented for `str`
Anche se la lunghezza del letterale «Hello, World!» può essere nota al momento della compilazione, in quanto str è una sequenza di dimensione sconosciuta.
Ma come riferimento a un letterale (&str), ha un «fat pointer», che contiene l'indirizzo e la lunghezza del letterale in memoria.
I fat pointer hanno una dimensione nota, quindi questa riga verrà compilata
const MY_CONST: &str = "Hello, World!";
Un binding mutabile a una string slice può avere il valore sostituito, ma non modificato sul posto.
Esempio
let mut my_str = "Hello, World!";
my_str = "Hi!";
let mut my_string = String::from("Hello");
my_string.push_str(", World!"); // there is no equivalent function to modify &str
È meno restrittivo usare &str invece di &String quando si definisce il parametro di una funzione: il codice seguente, infatti, non verrà compilato
pub fn main() {
let my_str: &str = "Hello, World!";
say_hi(my_str);
}
fn say_hi(phrase: &String) {
println!("{phrase:?}");
}
// mismatched types
// expected reference `&String`
// found reference `&str`
Un &str non subisce una coercizione verso un &String. Questo codice invece verrà compilato
pub fn main() {
let my_string = String::from("Hello, World!");
say_hi(&my_string)
}
fn say_hi(phrase: &str) {
println!("{phrase:?}");
}
Un &String subisce una coercizione verso un &str. Quindi usare &str come tipo di parametro sarà spesso più utile.