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)
为什么必须指定这种类型,特别是在这种情况下我们只存储对象的引用?如何才能使此代码生效?
所有类型在编译时都必须是静态已知的。如果 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
特征指定。
您需要指定特征的关联类型(即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 上查看此操作的实际效果