traduccion ps4 lenguaje language descargar rust

ps4 - rust traduccion



Conversión de la opción<String> a la opción<& str> (5)

Aquí hay una manera de hacerlo. Tenga en cuenta que debe mantener la String original, de lo contrario, ¿en qué &str sería una porción?

let opt = Some(String::from("test")); // kept around let unwrapped: &str = match opt.as_ref() { Some(s) => s, // deref coercion None => "default", };

playpen

Muy a menudo he obtenido una Option<String> de un cálculo, y me gustaría usar este valor o un valor predeterminado codificado.

Esto sería trivial con un número entero:

let opt: Option<i32> = Some(3); let value = opt.unwrap_or(0); // 0 being the default

Pero con String y a &str , el compilador se queja de tipos no coincidentes:

let opt: Option<String> = Some("some value".to_owned()); let value = opt.unwrap_or("default string");

El error exacto aquí es:

error[E0308]: mismatched types --> src/main.rs:4:31 | 4 | let value = opt.unwrap_or("default string"); | ^^^^^^^^^^^^^^^^ | | | expected struct `std::string::String`, found reference | help: try using a conversion method: `"default string".to_string()` | = note: expected type `std::string::String` found type `&''static str`

Una opción es convertir el segmento de cadena en una cadena propia, como lo sugiere rustc:

let value = opt.unwrap_or("default string".to_string());

Pero esto provoca una asignación, lo que no es deseable cuando quiero convertir de inmediato el resultado en un segmento de cadena, como en esta llamada a Regex::new() :

let rx: Regex = Regex::new(&opt.unwrap_or("default string".to_string()));

Prefiero convertir la Option<String> en una Option<&str> para evitar esta asignación.

¿Cuál es la forma idomática de escribir esto?


Aunque me encanta la respuesta de Veedrac (la usé), si la necesita en un punto y desea algo expresivo, puede usar as_ref() , map y String::as_str chain:

let opt: Option<String> = Some("some value".to_string()); assert_eq!(Some("some value"), opt.as_ref().map(String::as_str));


La biblioteca estándar tiene la función inestable nocturna solamente Option::deref para hacer esto:

#![feature(inner_deref)] fn main() { let opt: Option<String> = Some("some value".to_owned()); let value = opt.deref().unwrap_or("default string"); }


Puede usar as_ref() y map() para transformar una Option<String> en una Option<&str> .

fn main() { let opt: Option<String> = Some("some value".to_owned()); let value = opt.as_ref().map(|x| &**x).unwrap_or("default string"); }

Primero, as_ref() toma implícitamente una referencia en opt , dando una &Option<String> (porque as_ref() toma &self , es decir, recibe una referencia), y la convierte en una Option<&String> . Luego usamos map para convertirlo en una Option<&str> . Esto es lo que hace &**x : el más a la derecha * (que se evalúa primero) simplemente elimina la referencia de &String , dando un valor de String . Luego, el * más a la izquierda en realidad invoca el rasgo Deref , porque String implements Deref<Target=str> , dándonos un valor str . Finalmente, & toma la dirección del valor str , dándonos un &str .

Puede simplificar esto un poco más usando map_or para combinar map y unwrap_or en una sola operación:

fn main() { let opt: Option<String> = Some("some value".to_owned()); let value = opt.as_ref().map_or("default string", |x| &**x); }

Si &**x parece demasiado mágico, puedes escribir String::as_str en String::as_str lugar:

fn main() { let opt: Option<String> = Some("some value".to_owned()); let value = opt.as_ref().map_or("default string", String::as_str); }

o String::as_ref (del rasgo AsRef , que está en el prelude ):

fn main() { let opt: Option<String> = Some("some value".to_owned()); let value = opt.as_ref().map_or("default string", String::as_ref); }

o String::deref (aunque también necesita importar el rasgo Deref ):

use std::ops::Deref; fn main() { let opt: Option<String> = Some("some value".to_owned()); let value = opt.as_ref().map_or("default string", String::deref); }

Para que cualquiera de estos funcione, debe mantener un propietario para la Option<String> siempre que la Option<&str> o sin envolver &str deba permanecer disponible. Si eso es demasiado complicado, podrías usar Cow .

use std::borrow::Cow::{Borrowed, Owned}; fn main() { let opt: Option<String> = Some("some value".to_owned()); let value = opt.map_or(Borrowed("default string"), |x| Owned(x)); }


Una mejor manera podría ser implementar esto genéricamente para T: Deref :

use std::ops::Deref; trait OptionDeref<T: Deref> { fn as_deref(&self) -> Option<&T::Target>; } impl<T: Deref> OptionDeref<T> for Option<T> { fn as_deref(&self) -> Option<&T::Target> { self.as_ref().map(Deref::deref) } }

que efectivamente generaliza as_ref .