rust traits

rust - ¿Cómo devuelvo una instancia de un rasgo de un método?



traits (3)

Rust 1.26 y hasta

impl Trait ahora existe :

fn create_shader(&self) -> impl Shader { let shader = MyShader; shader }

Tiene limitaciones, como no poder ser utilizado en un método de rasgo y no puede usarse cuando el tipo de retorno concreto es condicional. En esos casos, debe utilizar la respuesta del objeto de rasgo a continuación.

Rust 1.0 y hasta

Debe devolver un objeto de rasgo de algún tipo, como &T o Box<T> , y tiene razón en que &T es imposible en este caso:

fn create_shader(&self) -> Box<Shader> { let shader = MyShader; Box::new(shader) }

Ver también:

  • ¿Cuál es la forma correcta de devolver un Iterador (o cualquier otro rasgo)?
  • Condicionalmente iterar sobre uno de varios posibles iteradores

Estoy tratando de crear una función que devuelve una instancia del rasgo Shader . Aquí está mi código simplificado drásticamente:

trait Shader {} struct MyShader; impl Shader for MyShader {} struct GraphicsContext; impl GraphicsContext { fn create_shader(&self) -> Shader { let shader = MyShader; shader } } fn main() {}

Sin embargo recibo el siguiente error:

error[E0277]: the trait bound `Shader + ''static: std::marker::Sized` is not satisfied --> src/main.rs:10:32 | 10 | fn create_shader(&self) -> Shader { | ^^^^^^ `Shader + ''static` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Shader + ''static` = note: the return type of a function must have a statically known size

Esto tiene sentido ya que el compilador no sabe el tamaño del rasgo, pero en ninguna parte puedo encontrar la manera recomendada de solucionar esto. Devolver una referencia con & no funcionaría hasta donde sé, porque la referencia duraría más que la vida de su creador.

Tal vez necesito usar la Box<T> ?


Creo que esto es lo que estabas buscando; Una simple fábrica implementada en Rust :

pub trait Command { fn execute(&self) -> String; } struct AddCmd; struct DeleteCmd; impl Command for AddCmd { fn execute(&self) -> String { "It add".into() } } impl Command for DeleteCmd { fn execute(&self) -> String { "It delete".into() } } fn command(s: &str) -> Option<Box<Command + ''static>> { match s { "add" => Some(Box::new(AddCmd)), "delete" => Some(Box::new(DeleteCmd)), _ => None, } } fn main() { let a = command("add").unwrap(); let d = command("delete").unwrap(); println!("{}", a.execute()); println!("{}", d.execute()); }


Creo que puedes usar los genéricos y el envío estático (no tengo idea si esos son los términos correctos, solo vi a alguien más usarlos) para crear algo como esto.

Esto no es exactamente "volver como un rasgo", pero es permitir que las funciones usen rasgos genéricamente. La sintaxis es un poco oscura, en mi opinión, por lo que es fácil pasarla por alto.

Pregunté Cómo usar iteradores genéricos en lugar de tipos de lista específicos sobre cómo devolver el rasgo del Iterator . Se pone feo

En el patio de recreo :

struct MyThing { name: String, } trait MyTrait { fn get_name(&self) -> String; } impl MyTrait for MyThing { fn get_name(&self) -> String { self.name.clone() } } fn as_trait<T: MyTrait>(t: T) -> T { t } fn main() { let t = MyThing { name: "James".to_string(), }; let new_t = as_trait(t); println!("Hello, world! {}", new_t.get_name()); }