TL; DR: Em vez disso &str
, pode-se usar &[T]
ou &T
permitir código mais genérico.
Um dos principais motivos para usar a String
ou a Vec
é porque eles permitem aumentar ou diminuir a capacidade. No entanto, quando você aceita uma referência imutável, não pode usar nenhum desses métodos interessantes no Vec
or String
.
Aceitar a &String
, &Vec
ou &Box
também exige que o argumento seja alocado no heap antes que você possa chamar a função. Aceitar a &str
permite um literal de cadeia de caracteres (salvo nos dados do programa) e aceitar uma &[T]
ou &T
permite uma matriz ou variável alocada por pilha. Alocação desnecessária é uma perda de desempenho. Isso geralmente é exposto imediatamente quando você tenta chamar esses métodos em um teste ou main
método:
awesome_greeting(&String::from("Anna"));
total_price(&vec![42, 13, 1337])
is_even(&Box::new(42))
Outra consideração de desempenho é que &String
, &Vec
e &Box
introduza uma camada desnecessária de indireção, pois você deve desreferenciar o &String
para obter um String
e executar uma segunda desreferência para terminar &str
.
Em vez disso, você deve aceitar uma fatia de string ( &str
), uma fatia ( &[T]
) ou apenas uma referência ( &T
). A &String
, &Vec<T>
ou &Box<T>
será automaticamente coagido a a &str
, &[T]
ou &T
, respectivamente.
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
}
Agora você pode chamar esses métodos com um conjunto mais amplo de tipos. Por exemplo, awesome_greeting
pode ser chamado com uma string literal ( "Anna"
) ou alocada String
. total_price
pode ser chamado com uma referência a uma matriz ( &[1, 2, 3]
) ou alocada Vec
.
Se você deseja adicionar ou remover itens do String
ou Vec<T>
, pode usar uma referência mutável ( &mut String
ou &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);
}
Especificamente para fatias, você também pode aceitar um &mut [T]
ou &mut str
. Isso permite que você modifique um valor específico dentro da fatia, mas não é possível alterar o número de itens dentro da fatia (o que significa que é muito restrito para cadeias):
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
é mais geral (como: impõe menos restrições) sem capacidade reduzida"? Além disso: o ponto 3 geralmente não é tão importante assim. Normalmente,Vec
s eString
s ficam na pilha e geralmente até em algum lugar próximo ao quadro atual da pilha. A pilha geralmente está quente e a desreferência será servida a partir de um cache da CPU.