Existem duas formas de o Rust implementar um array de caracteres: str e String.
str, também conhecido como "string slice", geralmente é usado com uma referência, como &str.
Para entender por quê, pode ajudar entender por que a linha de código a seguir não compila
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`
Mesmo que o comprimento do literal "Hello, World!" possa ser conhecido em tempo de compilação, como str ele é uma sequência de tamanho desconhecido.
Mas como uma referência a um literal (&str), ele tem um "ponteiro gordo" que guarda o endereço e o comprimento do literal na memória.
Ponteiros gordos têm tamanho conhecido, então esta linha vai compilar
const MY_CONST: &str = "Hello, World!";
Uma associação mutável a um string slice pode ter seu valor substituído, mas não modificado no lugar.
Exemplo
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
É menos limitante usar &str em vez de &String ao definir o parâmetro de uma função, já que isto não compila
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`
Um &str não sofre coerção para um &String. Mas isto vai compilar
pub fn main() {
let my_string = String::from("Hello, World!");
say_hi(&my_string)
}
fn say_hi(phrase: &str) {
println!("{phrase:?}");
}
Um &String sofre coerção para um &str. Então usar &str como tipo de parâmetro costuma ser mais útil.