0

I am trying to implement part of a UI framework. In the bottom example, the impl of widgets_mut() for Vec<T> needs to return a vector of trait objects like Vec<&mut dyn AnyWidget>. Given T is constrained to impl AnyWidget I don't understand why I am getting the error:

a value of type `Vec<&mut dyn AnyWidget>` cannot be built from an iterator over elements of type `&mut T`
the trait `FromIterator<&mut T>` is not implemented for `Vec<&mut dyn AnyWidget>`

Why does the 2-tuple implementation work, but the Vec implementation which seems equivalent doesn't?

fn main() {}

pub trait AnyWidget {}

pub trait WidgetVec {
    fn widgets_mut(&mut self) -> Vec<&mut dyn AnyWidget>;
}

// This implementation for a 2-tuple seems equivalent and works fine:
impl<W0: AnyWidget, W1: AnyWidget> WidgetVec for (W0, W1) {
    fn widgets_mut(&mut self) -> Vec<&mut dyn AnyWidget> {
        let mut v: Vec<&mut dyn AnyWidget> = Vec::with_capacity(2);
        v.push(&mut self.0);
        v
    }
}

impl<T: AnyWidget> WidgetVec for Vec<T> {
    fn widgets_mut(&mut self) -> Vec<&mut dyn AnyWidget> {
        self.iter_mut()
            .map(|child| child)
            .collect::<Vec<&mut dyn AnyWidget>>()
    }
}
Max888
  • 3,089
  • 24
  • 55
  • You need to cast `child` to `&mut dyn AnyWidget`. E.g. change `.map(|child| child)` to `.map(|child| child as &mut dyn AnyWidget)` or even just to `.map(|child| child as _)`, and the code compiles. – user4815162342 Oct 22 '22 at 00:30
  • 1
    awesome, thanks. If you put that in an answer I'll accept it. – Max888 Oct 22 '22 at 02:18
  • This is a very frequent (and sadly quite unnecessary) stumbling block with dynamic dispatch, so there are probably a bunch of dups. Now that someone has written one, it's fine to accept it, you don't need to wait for one from me. – user4815162342 Oct 22 '22 at 07:45
  • 1
    Also note that you don't need turbofish (explicit `::>()` in the call to `collect()` - since the function already has the return type spelled out, a simple `.collect()` will work just as nicely. – user4815162342 Oct 22 '22 at 07:46

1 Answers1

2

All you're missing is to explicitly cast the child from &mut T to &mut dyn AnyWidget.

impl<T: AnyWidget> WidgetVec for Vec<T> {
    fn widgets_mut(&mut self) -> Vec<&mut dyn AnyWidget> {
        self.iter_mut()
            .map(|child| child as &mut dyn AnyWidget)
            .collect::<Vec<&mut dyn AnyWidget>>()
    }
}

In some cases, rust will perform these kinds of conversions automatically (at "coercion sites"), but this can't be done here, because there isn't a coercion site where you're trying to cast child. See the reference on coercion sites for all the places this can be done.

Zoey Hewll
  • 4,788
  • 2
  • 20
  • 33