0

This is the sequel of this question

struct Int{
    i : i32
}


fn main() {

    let adder = move |x : &Int| Int{ i: x.i + 1}; 
    let v_adder=vec![adder];
    let i_adder=v_adder.iter();
    let nv_adder=i_adder.collect::<Vec<&dyn Fn(&Int)->Int>>();
}

I have a long error message with this sentence:

help: the trait FromIterator<&[closure@src/main.rs:8:17: 8:49]> is not implemented for Vec<&dyn for<'r> Fn(&'r Int) -> Int>

struct Int{ i : i32 }

fn main() {

    let adder = move |x : &Int| Int{ i: x.i + 1}; 
    let v_adder=vec![adder];
    let i_adder=v_adder.iter();
    let v = Vec::from_iter(i_adder);
    let p= v[0](&Int{i:1}).i;
    println!("{}",p)

}

But this code works fine. I use from_iter. It means that the trait FromIter is implemented.


updated after the kmdreko comment

I´ve change the first main function in order to replace &dyn for<'r> Fn(&'r Int) -> Int by impl Fn(&Int) -> Int>

let adder = move |x : &Int| Int{ i: x.i + 1}; 
let v_adder=vec![adder];
let i_adder=v_adder.iter();
let nv_adder=i_adder.collect::<Vec<impl Fn(&Int) -> Int>>();

error[E0562]: impl Trait only allowed in function and inherent method return types, not in path

  • 2
    `&[closure@...]` != `&dyn Fn(...)`. The same goes for any `&T` != `&dyn Trait`. The latter example works because you make a `Vec<&[closure@...]>` and not a `Vec<&dyn Fn(...)>` like the former example attempts. You need to *coerce* the `&T` into a `&dyn Trait` – kmdreko Aug 26 '22 at 16:00
  • @kmdreko thanks for your comment. I've tried to replace by the type proprosed when I use vec::fromIterator (see update). It doesn't work either. what I have done, is it what you mean or do you mean something else? – Pierre-olivier Gendraud Aug 26 '22 at 16:20
  • Why doesn't [this answer](https://stackoverflow.com/a/73497899) from your previous question resolve the problem entirely? Why haven't you applied the suggested approach of mapping the elements of the iterator into trait objects? – E_net4 Aug 26 '22 at 16:27
  • Some relevant questions: https://stackoverflow.com/questions/25818082/vector-of-objects-belonging-to-a-trait https://stackoverflow.com/questions/27957103/how-do-i-create-a-heterogeneous-collection-of-objects https://stackoverflow.com/questions/47156009/how-to-iterate-over-a-collection-of-structs-as-an-iterator-of-trait-object-refer Please see which one helps you the most. – E_net4 Aug 26 '22 at 16:28
  • @Pierre-olivierGendraud I've written an answer, but I'm still not sure what your actual *goal* is, if you want a `Vec<&dyn Fn(...)>` type because of the dynamicism or simply want something nameable then my answer is what you want. But if you want to collect into a `Vec` without naming the type (as one can't with closures) then just do `.collect::>()`. – kmdreko Aug 26 '22 at 16:32
  • There is a bigger problem behind all this, it's that, in general, you can't really build vectors of closures *as is*, because all closures have different types. See [this example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=39ce4b6621d9b392bdb2c7d75adc869b). – jthulhu Aug 26 '22 at 16:41
  • Agreed, @Pierre-olivierGendraud you usually want `Vec Int>>` from the start like the answer in your last question partially demonstrates. And shown in other answers that E_net4 has linked. – kmdreko Aug 26 '22 at 16:53

1 Answers1

3

A &T != &dyn Trait, even if T implements Trait. The former can be coerced into the latter, often transparently because things like passing function arguments or assigning to a variable are coercion sites. However, they are still different types (even have different sizes) and thus you can't collect into a collection for &dyn Trait from an iterator of &Ts.

To get this to work, you need to introduce a coercion from your iterator, via .map():

let nv_adder = v_adder.iter().map(|f| f as &dyn Fn(&Int) -> Int).collect::<Vec<_>>()

See the playground.

kmdreko
  • 42,554
  • 6
  • 57
  • 106