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

时间:2015-06-05 07:42:32

标签: rust traits

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

trait Shader {}

struct MyShader;
impl Shader for MyShader {}

struct GraphicsContext;

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

fn main() {}

但是我收到以下错误:

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

这是有道理的,因为编译器不知道特征的大小,但我无处可寻找修复它的推荐方法。 用&传回一个引用并不是我所知道的,因为引用会比它的创建者的生命周期更长。

也许我需要使用Box<T>

3 个答案:

答案 0 :(得分:23)

Rust 1.26及以上

impl Trait now exists

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

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

Rust 1.0及以上

您需要返回某种类型的特征对象,例如&TBox<T>,而您在此&T是不可能的。实例:

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

另见:

答案 1 :(得分:4)

我认为这就是你要找的东西; a simple factory implemented in 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());
}

答案 2 :(得分:0)

我认为您可以使用泛型和静态调度(我不知道这些是否是正确的术语,我只是看到其他人使用它们)来创建这样的东西。

这并不是&#34;作为特征返回&#34;,而是让函数一般使用特征。在我看来,语法有点模糊,所以很容易错过。

我问Using generic iterators instead of specific list types有关返回Iterator特征的问题。它变得丑陋。

In the playground

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());
}