在 Box 中指定通用实现以使用匹配项

  • 本文关键字:实现 Box rust
  • 更新时间 :
  • 英文 :


我想写一个函数,它返回实现共同特征的结构。

如果我的函数指定返回类型 -> impl MyTrait ,则在使用匹配时无法兼容,因为匹配必须返回相同的类型。例:

fn get_a_struct(an_enum: MyEnum) -> impl MyTrait {
    match an_enum {
        MyEnum::MyEnumFoo => MyStruct1 {},
        MyEnum::MyEnumBar => MyStruct2 {},
    }
}

它产生:

error[E0308]: match arms have incompatible types
  --> src/main.rs:22:5
   |
22 | /     match an_enum {
23 | |         MyEnum::MyEnumFoo => MyStruct1{},
24 | |         MyEnum::MyEnumBar => MyStruct2{},
   | |                              ------------- match arm with an incompatible type
25 | |     }
   | |_____^ expected struct `MyStruct1`, found struct `MyStruct2`
   |
   = note: expected type `MyStruct1`
              found type `MyStruct2`

如果我用Box尝试一下,像这样:

trait MyTrait {
    fn my_func() {}
}
enum MyEnum {
    MyEnumFoo,
    MyEnumBar,
}
struct MyStruct1 {}
struct MyStruct2 {}
impl MyTrait for MyStruct1 {
    fn my_func() {
        println!("Hello world from MyStruct1")
    }
}
impl MyTrait for MyStruct2 {
    fn my_func() {
        println!("Hello world from MyStruct2")
    }
}
fn get_a_struct(an_enum: MyEnum) -> Box<MyTrait> {
    match an_enum {
        MyEnum::MyEnumFoo => Box::new(MyStruct1 {}),
        MyEnum::MyEnumBar => Box::new(MyStruct2 {}),
    }
}
error[E0038]: the trait `MyTrait` cannot be made into an object
  --> src/main.rs:21:1
   |
21 | fn get_a_struct(an_enum: MyEnum) -> Box<MyTrait> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyTrait` cannot be made into an object
   |
   = note: method `my_func` has no receiver

在这种情况下,我不知道如何使用特征。

如何编写一个返回实现相同特征的结构的函数?

部分响应可以在为什么 impl trait 不能用于返回多个/条件类型?中找到,但没有一个答案解决对象安全问题。

OOP 中的类似行为可以通过接口指定返回类型。

正如编译器消息所说,您需要向my_func方法添加一个接收器:fn my_func() -> fn my_func(&self)

这是必要的原因是因为它需要object-safe。RFC-0255 中详细介绍了这些要求

您的案件的具体要求是

必须具有类型为 Self 或取消引用 Self类型;

现在,这意味着self&self&mut selfself: Box<Self>,但最终这应该扩展到自定义类型,如self: Rc<Self>等。

use std::fmt::Debug;
fn main() {
    println!("Foo => {:?}", get_a_struct(MyEnum::MyEnumFoo));
    println!("Bar => {:?}", get_a_struct(MyEnum::MyEnumBar));
}
trait MyTrait :Debug{
    fn my_func(&self) {}
}
enum MyEnum {
    MyEnumFoo,
    MyEnumBar,
}
#[derive(Debug)]
struct MyStruct1 {}
#[derive(Debug)]
struct MyStruct2 {}
impl MyTrait for MyStruct1 {
    fn my_func(&self) {
        println!("Hello world from MyStruct1")
    }
}
impl MyTrait for MyStruct2 {
    fn my_func(&self) {
        println!("Hello world from MyStruct2")
    }
}
fn get_a_struct(an_enum: MyEnum) -> Box<dyn MyTrait> {
    match an_enum {
        MyEnum::MyEnumFoo => Box::new(MyStruct1 {}),
        MyEnum::MyEnumBar => Box::new(MyStruct2 {}),
    }
}

最新更新