如何从方法返回特征实例?

neo*_*n64 25 traits rust

我正在尝试创建一个返回Shader特征实例的函数.这是我极为简化的代码:

trait Shader {}

struct MyShader;
impl Shader for MyShader {}

struct GraphicsContext;

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

fn main() {}
Run Code Online (Sandbox Code Playgroud)

但是我收到以下错误:

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
Run Code Online (Sandbox Code Playgroud)

这是有意义的,因为编译器不知道特征的大小,但我无处可寻找修复它的推荐方法.&由于引用会比其创建者的生命周期更长,因此传回引用将无法正常工作.

也许我需要使用Box<T>

Ste*_*nik 27

Rust 1.26及以上

impl Trait现在存在:

fn create_shader(&self) -> impl Shader {
    let shader = MyShader;
    shader
}
Run Code Online (Sandbox Code Playgroud)

它确实有一些限制,例如无法在特征方法中使用,并且当具体返回类型是有条件的时,它不能使用.在这些情况下,您需要使用下面的特征对象答案.

Rust 1.0及以上

你需要返回一种某种特征对象,例如&T或者Box<T>,你是对的,&T在这种情况下是不可能的:

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

也可以看看:

  • 简而言之,因为语言不支持。该语言尚不支持它,因为这需要更多我们尚未完成的类型系统机制。 (4认同)
  • 值得指出的是,“impl Trait”实际上创建了一个*通用*函数,它使用*静态*多态性。因此,如果目标是具有动态多态性(又名在运行时改变行为),那么最好返回一个(装箱的)特征对象,又名“Box&lt;dyn Shader&gt;”。 (2认同)

Cri*_*ira 6

我想这就是你要找的东西;一个用 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());
}
Run Code Online (Sandbox Code Playgroud)