这个问题在这里已有答案:
我想写一个函数,它返回实现共同特征的结构。
如果我的函数指定了返回类型-> 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中的类似行为可以通过接口指定返回类型。
正如编译器消息所说,你需要在my_func
方法中添加一个接收器:fn my_func()
- > fn my_func(&self)
这是必要的原因是因为它需要是object-safe
。 RFC-0255详细说明了这些要求
您案件的具体要求是
必须有一个类型为
Self
的接收器或者对Self
类型的解引用;现在,这意味着
self
,&self
,&mut self
或self: 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 {}),
}
}