una tipos sub referencia print por pasar parametros objetos imprimir funciones funcion desde con como string reference rust borrowing

tipos - ¿Por qué se desaconseja aceptar una referencia a un String(& String), Vec(& Vec) o Box(& Box) como argumento de función?



sub con parametros vba excel (2)

Además de la respuesta de Shepmaster , otra razón para aceptar a &str (y de manera similar &[T] etc.) se debe a todos los otros tipos, además de String y &str que también satisfacen a Deref<Target = str> . Uno de los ejemplos más notables es Cow<str> , que le permite ser muy flexible acerca de si se trata de datos propios o prestados.

Si usted tiene:

fn awesome_greeting(name: &String) { println!("Wow, you are awesome, {}!", name); }

Pero debes llamarlo con una Cow<str> , tendrás que hacer esto:

let c: Cow<str> = Cow::from("hello"); // Allocate an owned String from a str reference and then makes a reference to it anyway! awesome_greeting(&c.to_string());

Cuando cambia el tipo de argumento a &str , puede usar Cow sin problemas, sin ninguna asignación innecesaria, al igual que con String :

let c: Cow<str> = Cow::from("hello"); // Just pass the same reference along awesome_greeting(&c); let c: Cow<str> = Cow::from(String::from("hello")); // Pass a reference to the owned string that you already have awesome_greeting(&c);

Aceptar &str hace 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 con Cow<[T]> etc.

Escribí un código Rust que toma un &String como argumento:

fn awesome_greeting(name: &String) { println!("Wow, you are awesome, {}!", name); }

También he escrito código que toma una referencia a un Vec o Box :

fn total_price(prices: &Vec<i32>) -> i32 { prices.iter().sum() } fn is_even(value: &Box<i32>) -> bool { **value % 2 == 0 }

Sin embargo, recibí algunos comentarios de que hacerlo así no es una buena idea. Por qué no?


TL; DR: en su lugar, se puede usar &str , &[T] o &T para permitir un código más genérico.

  1. Una de las razones principales para usar una String o una Vec es porque permiten aumentar o disminuir la capacidad. Sin embargo, cuando acepta una referencia inmutable, no puede usar ninguno de esos métodos interesantes en Vec o String .

  2. Aceptar una &String , &Vec o &Box también requiere que el argumento se asigne en el montón antes de poder llamar a la función. Aceptar a &str permite un literal de cadena (guardado en los datos del programa) y aceptar a &[T] o &T permite 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 método main :

    awesome_greeting(&String::from("Anna"));

    total_price(&vec![42, 13, 1337])

    is_even(&Box::new(42))

  3. Otra consideración de rendimiento es que &String , &Vec y &Box introducen una capa innecesaria de indirección, ya que debe desreferenciar &String para obtener una String y luego realizar una segunda desreferencia para terminar en &str .

En su lugar, debe aceptar un segmento de cadena ( &str ), un segmento ( &[T] ) o simplemente una referencia ( &T ). A &String , &Vec<T> o &Box<T> se convertirán automáticamente en 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_greeting se puede llamar con un literal de cadena ( "Anna" ) o una String asignada. total_price puede llamar a total_price con una referencia a una matriz ( &[1, 2, 3] ) o un Vec asignado.

Si desea agregar o eliminar elementos de String o Vec<T> , puede tomar una referencia mutable ( &mut String o &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 a &mut [T] o &mut str . Esto le permite mutar un valor específico dentro del segmento, pero no puede cambiar la cantidad de elementos dentro del segmento (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(); } }