在Box中指定常用实现以使用匹配[duplicate]

问题描述 投票:1回答:1

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

如果我的函数指定了返回类型-> 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

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

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

可以在Why can impl trait not be used to return multiple / conditional types?中找到部分响应,但没有一个答案解决了对象安全问题。

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

rust
1个回答
1
投票

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

这是必要的原因是因为它需要是object-safeRFC-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 {}),
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.