如以下代码所示:
trait T2impl {}
struct S4T2impl;
impl T2impl for S4T2impl{}
trait TimplMethod {
fn f() -> impl T2impl;
}
struct S4TimplMethod;
impl TimplMethod for S4TimplMethod {
fn f() -> impl T2impl {
S4T2impl
}
}
fn f1() -> impl TimplMethod {
S4TimplMethod
}
// so far so good
// but I want to return one of more TimplMethod implementations, so I need a dynamic approach:
// fn f2() -> Box<dyn TimplMethod> {
// Box::new( S4TimplMethod)
// }
我收到错误消息:
error[E0038]: the trait `TimplMethod` cannot be made into an object
--> src/main.rs:158:18
|
158 | fn f2() -> Box<dyn TimplMethod> {
| ^^^^^^^^^^^^^^^ `TimplMethod` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> src/main.rs:140:7
如何解决这个问题?
我猜返回类型不是 Self,这是您案例中的主要问题。方法 f 返回 impl T2impl,它本质上是 Self 的替代品,使其不是对象安全的。此外,方法不使用泛型类型参数。所以试试这个:
impl TimplMethod for S4TimplMethod {
fn f() -> S4T2impl {
S4T2impl
}
}
然后 2. 在方法返回中使用 Trait 对象 更改 f 的返回类型以返回特征对象 (Box)。这种方法保持了灵活性,但涉及动态调度和堆分配。
trait TimplMethod {
fn f() -> Box<dyn T2impl>;
}
impl TimplMethod for S4TimplMethod {
fn f() -> Box<dyn T2impl> {
Box::new(S4T2impl)
}
}
如果可能,重构你的特质并使用枚举而不是特质
如果您无法更改
TimplMethod
,您可以创建一个对象安全的辅助特征,该特征为定义 TimplMethod
的所有类型定义,并返回:
// TimplMethod and its implementers unchanged
trait TimplMethodErased {
fn f(&self) -> Box<dyn T2impl + '_>;
}
impl<T> TimplMethodErased for T where T: TimplMethod {
fn f(&self) -> Box<dyn T2impl + '_> {
Box::new(T::f())
}
}
fn f1() -> Box<dyn TimplMethodErased> {
Box::new(S4TimplMethod)
}