Search code examples
rusttype-conversiontrait-objects

Getting a slice of trait objects from a slice of an associated type


I have two related traits List and ListItem (playground link).

trait List {
    type Item: ListItem;
    fn items(&self) -> Vec<Self::Item>;
    /* more stuff */
}

where Item is an associated type on List and ListItem has a custom implementation for PartialEq and Debug

Inside of a List trait method that looks like

fn foo(&self, other: &dyn List<Item=Self::Item>)

I would like to compare sub-slices of the items, using the PartialEq defined for ListItem. e.g.

let lhs: &[&dyn ListItem] = ...;
let rhs: &[&dyn ListItem] = ...;
assert_eq!(lhs, rhs);

but I cannot coerce the slices to the correct type.

fn foo(&self, other: &dyn List<Item = Self::Item>) {
   let items = self.items();
   let items_slice: &[&dyn ListItem] = items.as_slice(); // <-- Error here
error[E0308]: mismatched types
   |
40 |         let these: &[&dyn ListItem] = these_items.as_slice();
   |                    ----------------   ^^^^^^^^^^^^^^^^^^^^^^ expected `&[&dyn ListItem]`, found `&[<Self as List>::Item]`
   |                    |
   |                    expected due to this
   |
   = note: expected reference `&[&dyn ListItem]`
              found reference `&[<Self as List>::Item]`
   = help: consider constraining the associated type `<Self as List>::Item` to `&dyn ListItem`
   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html

(playground link)

How can I coerce the slice to the correct type?


Solution

  • You cannot. First, you need references, and items contains owned items. Second, you need fat references, and items has concrete types.

    You need to collect them into a Vec:

    let items = self.items();
    let items_dyn = items
        .iter()
        .map(|item| item as &dyn ListItem)
        .collect::<Vec<_>>();