这是一个令人讨厌的例子:
// 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);
}
我得到了:
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
为什么必须指定此类型,特别是在这种情况下我们只存储对象的引用?如何才能使此代码生效?
答案 0 :(得分:2)
您需要指定特征的关联类型(即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);
}
}
中查看此内容
答案 1 :(得分:0)
因此,第一个问题的答案已包含在Tim's answer中,并且是正确的,您可能不希望您的Example
是通用的。在这种情况下,您需要使用某种类型的擦除:
// 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 AnyBehaviour {
closure: Box<Fn()>,
}
impl AnyBehaviour {
fn new<U: SubBehaviour, T: Behaviour<Sub = U>>(b: &T) -> Self {
let closure = || {
//let sub = T::Sub::new();
println!("Can use T here");
};
AnyBehaviour {
closure: Box::new(closure),
}
}
}
// Struct that holds a collection of these traits.
struct Example {
behaviours: Vec<AnyBehaviour>,
}
impl Example {
fn add_behaviour<U: SubBehaviour, T: Behaviour<Sub = U>>(&mut self, b: &T) {
self.behaviours.push(AnyBehaviour::new(b));
}
}
fn main() {
let b = A;
let mut e = Example {
behaviours: Vec::new(),
};
e.add_behaviour(&b);
}
在闭包内,您可以访问所有需要的类型,并使用所需的任何子类型调用traits函数。
为什么会发生这种情况,主要是因为您实际上需要关联类型的定义才能使特征“完整”,以便编译器可以使用它。 Tims的回答是,根据定义,答案是在链中更高(在Example之外),而不是内部。
答案 2 :(得分:0)
所有类型在编译时必须是静态已知的。如果Rust允许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
}
尽管如此,您仍处在正确的道路上。我假设您介绍了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();
}
唯一的限制是,在Behaviour
的定义中,您无法执行任何取决于T
大小的操作(例如,将其分配到堆栈上或将其移动),因为T
不能由SubBehaviour
特性指定。