How to create a vector of boxed closures in Rust?

瘦欲@ 提交于 2019-12-05 05:26:17

The problem is that type inference has kicked in before you wanted it to. Conceptually, it's like this:

let mut xs: Vec<_> = Vec::new();
xs.push(Type1);
xs.push(Type2);

When the first value is seen, the type of the Vec's elements is inferred to be of that type. The second element then causes a mismatch.

Even when you Box the values, you have the same problem:

let mut xs: Vec<_> = Vec::new();
xs.push(Box::new(Type1));
xs.push(Box::new(Type2));

Looking at it another way, you never actually created a trait object. You have a Box<ConcreteType>, not a Box<dyn Trait>.

The solution is to cast the boxed concrete types to the boxed trait object:

let mut xs: Vec<_> = Vec::new();
xs.push(Box::new(Type1) as Box<dyn Trait>);
xs.push(Box::new(Type2) as Box<dyn Trait>);

The second push can have the type coerced automatically, so you can choose to leave the as bit off of that line.

Rolling this back up to the original problem:

let xs: Vec<_> = vec![
    Box::new(move |(x, y)| (y, x)) as Box<dyn Fn((i32, i32)) -> (i32, i32)>,
    Box::new(move |(x, y)| (1 - y, 1 - x)),
];

Or you can avoid the inference at all by specifying the type on the variable, my preferred style for this:

let xs: Vec<Box<dyn Fn((i32, i32)) -> (i32, i32)>> = vec![
    Box::new(move |(x, y)| (y, x)),
    Box::new(move |(x, y)| (1 - y, 1 - x)),
];
kazemakase

You should read the suggestion in the error message as "consider boxing your closure and using it as a trait object, or using it just as a trait object".

Using trait object references without boxing them will not work here because nothing owns the closures. The references in the vector would outlive the closures:

// This fails
let xs: Vec<&Fn((i32, i32)) -> (i32, i32)> = vec![ 
    &move |(x, y)| (y, x), 
    &move |(x, y)| (1 - y, 1 - x),
];

The vector needs to take ownership of the closures, which is where boxing the trait objects comes into play:

let xs: Vec<Box<Fn((i32, i32)) -> (i32, i32)>> = vec![ 
    Box::new(move |(x, y)| (y, x)), 
    Box::new(move |(x, y)| (1 - y, 1 - x)),
];

This explicitly tells the compiler that the vector can contain boxes of any closure with the same interface.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!