TL; DR: En su lugar &str, se puede usar &[T]o &Tpermitir un código más genérico.
Una de las principales razones para utilizar a Stringo a Veces porque permiten aumentar o disminuir la capacidad. Sin embargo, cuando acepta una referencia inmutable, no puede utilizar ninguno de esos métodos interesantes en Veco String.
Aceptar un &String, &Veco &Boxtambién requiere que el argumento se asigne en el montón antes de poder llamar a la función. Aceptar un &strpermite un literal de cadena (guardado en los datos del programa) y aceptar un &[T]o &Tpermite una matriz o variable asignada a la pila. La asignación innecesaria es una pérdida de rendimiento. Esto generalmente se expone de inmediato cuando intenta llamar a estos métodos en una prueba o un mainmétodo:
awesome_greeting(&String::from("Anna"));
total_price(&vec![42, 13, 1337])
is_even(&Box::new(42))
Otra consideración de rendimiento es eso &String, &Vece &Boxintroducir una capa innecesaria de indirección, ya que debe eliminar la referencia &Stringpara obtener una Stringy luego realizar una segunda desreferencia para terminar en &str.
En su lugar, debe aceptar una cadena de segmento ( &str), un segmento ( &[T]) o simplemente una referencia ( &T). A &String, &Vec<T>o &Box<T>será automáticamente coaccionado a a &str, &[T]o &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
}
Ahora puede llamar a estos métodos con un conjunto más amplio de tipos. Por ejemplo, awesome_greetingse puede llamar con una cadena literal ( "Anna") o un archivo String. total_pricese puede llamar con una referencia a una matriz ( &[1, 2, 3]) o un archivo Vec.
Si desea agregar o eliminar elementos del Stringo Vec<T>, puede tomar una referencia mutable ( &mut Stringo &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);
}
Específicamente para sectores, también puede aceptar &mut [T]o &mut str. Esto le permite mutar un valor específico dentro del sector, pero no puede cambiar la cantidad de elementos dentro del sector (lo que significa que está muy restringido para las cadenas):
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();
}
}
&stres más general (como en: impone menos restricciones) sin capacidades reducidas"? Además, creo que el punto 3 no suele ser tan importante. Por lo general,VecsyStrings vivirán en la pila y, a menudo, incluso cerca del marco de pila actual. La pila suele estar caliente y la desreferenciación se realizará desde una memoria caché de la CPU.total_price(&prices[0..4])no requiere la asignación de un nuevo vector para el segmento.&stry por eso (que viene de Python, así que por lo general no se ocupan explícitamente de tipos). Aclaró todo eso perfectamenteAdemás de la respuesta de Shepmaster , otra razón para aceptar a
&str(y de manera similar,&[T]etc.) es porque todos los otros tipos ademásStringy&streso también satisfacenDeref<Target = str>. Uno de los ejemplos más notables es elCow<str>que le permite ser muy flexible sobre si se trata de datos propios o prestados.Si usted tiene:
Pero debes llamarlo con a
Cow<str>, tendrás que hacer esto:Cuando cambia el tipo de argumento a
&str, puede usarloCowsin problemas, sin ninguna asignación innecesaria, al igual que conString:Aceptar
&strhace que llamar a su función sea más uniforme y conveniente, y la forma "más fácil" ahora también es la más eficiente. Estos ejemplos también funcionarán conCow<[T]>etc.fuente