Existem duas formas de o Rust implementar um array de carateres: str e String.
O str, também conhecido como «string slice», costuma usar-se com uma referência, como &str.
Para perceberes porquê, ajuda perceber por que razão a seguinte linha de código 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`
Embora o comprimento do literal "Hello, World!" possa ser conhecido em tempo de compilação, enquanto str é uma sequência de tamanho desconhecido.
Mas, enquanto referência a um literal (&str), tem um «fat pointer», que guarda o endereço e o comprimento do literal em memória.
Os fat pointers têm um tamanho conhecido, por isso esta linha compila.
const MY_CONST: &str = "Hello, World!";
Uma ligação mutável a um string slice pode ver o seu valor substituído, mas não modificado no local.
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 restritivo usar &str em vez de &String ao definir o parâmetro de uma função, pois 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 compila.
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. Por isso, usar &str como tipo de parâmetro é muitas vezes mais útil.