Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

Here is an offending example (Playground):

// 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 dyn 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);
}

I get:

error[E0191]: the value of the associated type `Sub` (from trait `Behaviour`) must be specified
  --> src/main.rs:17:29
   |
3  |     type Sub: SubBehaviour;
   |     ----------------------- `Sub` defined here
...
17 |     behaviours: Vec<&'a dyn Behaviour>,
   |                             ^^^^^^^^^ help: specify the associated type: `Behaviour<Sub = Type>`

Why must this type must be specified, particularly in this case where we are only storing a reference to the object? How can I get this code to work?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
1.0k views
Welcome To Ask or Share your Answers For Others

1 Answer

All types must be statically known at compile time. If Rust would allow different associated types for elements of a Vec, type information could depend on indices which are only known at runtime.

I find it helpful to consider a smaller example:

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
}

You were on the right track to fixing this though. I assume you introduced the SubBehaviour trait because you realized you need to put restrictions of what T can be. The thing is, in that case you don't need an associated type anymore.

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

The only limitation is that in your definition of Behaviour you can not do anything which would depend on the size of T, (like allocating it on the stack or moving it) since the size of T can not be specified by the SubBehaviour trait.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...