为什么必须在实现特征的类型的引用集合中指定关联类型?

Ros*_*hur 6 polymorphism traits rust

这是一个令人讨厌的例子:

// Some traits
trait Behaviour {
    type Sub: SubBehaviour;
}
trait SubBehaviour {}

// Some implementations of these traits
struct A;
impl Behaviour for A {
    type Sub = B;
}
struct B;
impl SubBehaviour for B {}

// Struct that holds a collection of these traits.
struct Example<'a> {
    behaviours: Vec<&'a Behaviour>,
}

impl<'a> Example<'a> {
    fn add_behaviour<T: Behaviour>(&mut self, b: &'a T) {
        self.behaviours.push(b);
    }
}

fn main() {
    let b = A;
    let mut e = Example {
        behaviours: Vec::new(),
    };
    e.add_behaviour(&b);
}
Run Code Online (Sandbox Code Playgroud)

操场

我正进入(状态:

error[E0191]: the value of the associated type `Sub` (from the trait `Behaviour`) must be specified
  --> src/main.rs:17:25
   |
17 |     behaviours: Vec<&'a Behaviour>,
   |                         ^^^^^^^^^ missing associated type `Sub` value
Run Code Online (Sandbox Code Playgroud)

为什么必须指定这种类型,特别是在这种情况下我们只存储对象的引用?如何才能使此代码生效?

Mar*_*ein 7

所有类型在编译时都必须是静态已知的。如果 Rust 允许 a 的元素具有不同的关联类型Vec,则类型信息可能取决于仅在运行时已知的索引。

我发现考虑一个较小的例子很有帮助:

trait Behaviour {
    type T;

    fn make_t(&self) -> T;
}

fn foo(my_vec: Vec<&dyn Behaviour>, index: usize) {
    let t = my_vec[index].make_t(); //Type of t depends on index
}
Run Code Online (Sandbox Code Playgroud)

不过,您走在正确的道路上来解决这个问题。我假设你引入了这个SubBehaviour特性,因为你意识到你需要对T可以是什么进行限制。问题是,在这种情况下,您不再需要关联类型。

trait SubBehaviour {}

trait Behaviour {
    fn make_t(&self) -> Box<dyn SubBehaviour>;

    fn ref_t(&self) -> &dyn SubBehaviour; // also fine
}

fn some_function(my_vec: Vec<&dyn Behaviour>, index: usize) {
    let t1 = my_vec[index].make_t();
}
Run Code Online (Sandbox Code Playgroud)

唯一的限制是,在你的定义中,Behaviour你不能做任何取决于 , 大小的事情T(比如在堆栈上分配它或移动它),因为 的大小T不能由SubBehaviour特征指定。


Tim*_*ann 4

您需要指定特征的关联类型(即Behavior<Sub = ???>)。

当在所有地方添加关联类型时,它会编译:

struct Example<'a, S: SubBehaviour + 'a> {
    behaviours: Vec<&'a Behaviour<Sub = S>>,
}

impl<'a, S: SubBehaviour> Example<'a, S> {
    fn add_behaviour<T: Behaviour<Sub = S>>(&mut self, b: &'a T) {
        self.behaviours.push(b);
    }
}
Run Code Online (Sandbox Code Playgroud)

在 Playground 上查看此操作的实际效果

  • 这并没有真正回答OP关于*为什么*的问题。他们已经知道他们需要指定类型...... (7认同)