当函数中包含一个返回 impl 特征的方法时,如何动态地从函数返回 impl 特征?

问题描述 投票:0回答:2

如以下代码所示:

  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

如何解决这个问题?

rust dynamic traits implementation box
2个回答
0
投票

我猜返回类型不是 Self,这是您案例中的主要问题。方法 f 返回 impl T2impl,它本质上是 Self 的替代品,使其不是对象安全的。此外,方法不使用泛型类型参数。所以试试这个:

  1. 返回具体类型而不是 impl Trait 不使用 impl T2impl,而是直接指定 f 将返回的具体类型。这使得特征对象安全,但降低了灵活性,因为您被锁定到特定的返回类型。
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)
    }
}

如果可能,重构你的特质并使用枚举而不是特质


0
投票

如果您无法更改

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

游乐场

© www.soinside.com 2019 - 2024. All rights reserved.