error[E0308]: mismatched types
--> src/main.rs:7:14
|
4 | let closures_1 = || {};
| ----- the expected closure
...
7 | let v2 = vec![closures_1, closures_2,]; // ❌
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected slice, found array of 2 elements
|
= note: expected struct `Box<[[closure@src/main.rs:4:22: 4:27]], _>`
found struct `Box<[fn(); 2], std::alloc::Global>`
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
为什么?
1
共 4 条评论, 1 页
评论区
写评论赞成 eweca-d 的观点。以下是我的理解和补充。 根据 reference 的类型分类,至少有以下一些类型与函数/闭包有关:
fn foo<T>() { }
,每个函数都是不同的类型type Binop = fn(i32, i32) -> i32;
—— written using thefn
keyword, refer to a function whose identity is not necessarily known at compile-time —— 相同签名的函数/非捕获闭包可以强制转化为相同的类型。注意这里是 小 f。dyn Fn(usize) -> usize
,动态分发。注意这里是 大 F。impl Fn(usize) -> usize
或者F: Fn(usize) -> usize
,静态分发_
:编译器推断类型而且前三者有 如下 coercion 关系:
相同签名的函数
报错的那行有这样的提示:
即:
fn(u32) -> i32 {fn_name}
in error messages切片和数组这两种不同的类型在这里不是重点,根据 playground 的 expand macro 功能,可以清楚地看到,
vec!
宏被展开成:这说明了三点问题:
let _ = [add, add2];
呢。这很难讲。安全本来就不是绝对的,从绝对的角度看,一切隐式都不应该存在:比如隐式/强制转换、强制解引用等。一方面,如果没有这些方便的“隐式”做法,写代码也太累了;另一方面,隐式带来未知,增加设计障碍和学习障碍。性能、安全、人体工学相互牵制,没有语言可以做到完美。相同签名的闭包
闭包使用起来很容易,但是它很特殊,从而带来复杂性(性能、安全、人体工学 金三角 again...):
例子正如楼主和 eweca-d 贴出的。而且涉及到上面 7 种罗列的大部分类型。
p.s. 我写的
Vec::from([closures_1, closures_2]);
通过编译,是因为impl<T, const N: usize> From<[T; N]> for Vec<T, Global>
性质,只要[closures_1, closures_2]
能编译,Vec::from
就能编译。因为实际上类型是不一样的,这个提示可能没说清楚,如果使用如下代码:
报错信息:
这个报错提示就比较明显了,因为所有闭包,哪怕是完全一致的,都是不同的type(类型)。
可以看看相关的帖子:
https://stackoverflow.com/questions/29371914/what-is-the-inferred-type-of-a-vector-of-closures https://stackoverflow.com/questions/39083375/expected-closure-found-a-different-closure
简单来说,编译器会为每一个闭包生成一个名字不同的结构体,其中包含有捕获的变量和函数指针。所以类型都是不同的。 至于指定类型为Vec<fn()>什么可以用我没想通,可能fn()提示会让vec里加入的是函数指针吧。至于为什么不能自动推断出这个,第一个帖子认为,这相当于把一个concrete type(固定类型)转换为类似object trait,涉及到动态派发,不是zero overhead,所以需要你手动指定才行。
let v2:Vec<fn()> = vec![closures_1, closures_2,];
这样指定类型就行,不过最好还是Box一下let v2:Vec<Box<dyn Fn()>> = vec![Box::new(closures_1), Box::new(closures_2)];
,不box的话你闭包只要捕获变量就不能用fn()了看报错是
vec
宏的问题,但是的确可以存在 Vec 中: