问题描述
以前被问到有关创建函数数组的问题,这些函数从中返回整数一个范围。最终的解决方案是将地图/集合放入 Vec< _>
。
我有一个相似但又不同的情况,即我的闭包具有相同的签名但实现不同。我尝试过这样:
让xs:Vec< _> = vec![
move |(x,y)| (y,x),
移动|(x,y)| (1-y,1-x),
];
我得到的错误:
错误[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中创建盒装封闭向量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!