如何在Rust中创建盒装封闭向量? [英] How to create a vector of boxed closures in Rust?

查看:61
本文介绍了如何在Rust中创建盒装封闭向量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以前一个问题被问到有关创建函数数组的问题,这些函数从中返回整数一个范围。最终的解决方案是将地图/集合放入 Vec< _>



我有一个相似但又不同的情况,即我的闭包具有相同的签名但实现不同。我尝试过这样:

 让xs:Vec< _> = vec![
move |(x,y)| (y,x),
移动|(x,y)| (1-y,1-x),
];

我得到的错误:



<上课前= lang-none prettyprint-override> 错误[E0308]:类型不匹配的
-> src / main.rs:4:9
|
4 |移动|(x,y)| (1-y,1-x),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^预期的关闭,找到了另一个关闭
|
=注意:预期类型`[closure@src/main.rs:3:9:3:29]`
发现类型`[closure@src/main.rs:4:9:4: 37]`
=注意:没有两个闭包,即使相同,也没有相同的类型
=帮助:考虑将闭包装箱和/或将其用作特征对象

我尝试了拳击:

 让xs:Vec _。 = vec![
Box :: new(move | x:u8,y:u8 |(y,x)),
Box :: new(move | x:u8,y:u8 |( 1-y,1-x)),
];

我又遇到了相同的错误:

  error [E0308]:类型不匹配的
-> src / main.rs:4:18
|
4 | Box :: new(移动| x:u8,y:u8 |(1-y,1-x)),
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
=注意:预期类型`[closure@src/main.rs:3:18:3:44]`
发现类型`[closure@src/main.rs:4:18:4: 52]`
=注意:没有两个闭包,即使相同,也没有相同的类型
=帮助:考虑将闭包装箱和/或将其用作特征对象

什么是正确的框封闭方式,以便可以将它们放入向量(或数组)中?

解决方案

问题是类型推断已经在您希望的时候开始了。从概念上讲,它是这样的:

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

看到第一个值时, Vec 的元素被推断为该类型。然后,第二个元素导致不匹配。



即使您 Box 值,也有相同的问题:

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

换一种方式来看,您实际上从未创建过特征对象。您有一个 Box< ConcreteType> ,而不是 Box< dyn Trait>



解决方案是将装箱的具体类型转换为装箱特征对象

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

second push 可以自动强制类型,因此您可以选择将 as 位保留在该行的外面。



将其追溯到原始问题:

  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)),
];

或者您可以通过在变量中指定类型来完全避免推断,这是我的首选样式:

  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)),
];


Previously a question was asked about creating an array of functions where the functions returned integers from a range. The final solution was to do a map/collect into a Vec<_>.

I have a similar yet different situation where I have closures with the same signature but different implementations. I tried this:

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

The error I get back:

error[E0308]: mismatched types
 --> src/main.rs:4:9
  |
4 |         move |(x, y)| (1 - y, 1 - x),
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
  |
  = note: expected type `[closure@src/main.rs:3:9: 3:29]`
             found type `[closure@src/main.rs:4:9: 4:37]`
  = note: no two closures, even if identical, have the same type
  = help: consider boxing your closure and/or using it as a trait object

I tried boxing:

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

I get back the same error:

error[E0308]: mismatched types
 --> src/main.rs:4:18
  |
4 |         Box::new(move |x: u8, y: u8| (1 - y, 1 - x)),
  |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
  |
  = note: expected type `[closure@src/main.rs:3:18: 3:44]`
             found type `[closure@src/main.rs:4:18: 4:52]`
  = note: no two closures, even if identical, have the same type
  = help: consider boxing your closure and/or using it as a trait object

What is the right way to box closures so that they can be put into a vector (or an array)?

解决方案

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)),
];

这篇关于如何在Rust中创建盒装封闭向量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆