Rust 代码如下:
trait Test: Sized {
fn test(self, f: impl FnOnce(Self)) {
f(self)
}
}
impl<T> Test for T {}
fn foo<T>(f: impl FnOnce(T)) {
|x| x.test(f);
}
编译错误:
error[E0282]: type annotations needed
--> src/lib.rs:9:6
|
9 | |x| x.test(f);
| ^ - type must be known at this point
|
help: consider giving this closure parameter an explicit type
|
9 | |x: _| x.test(f);
| +++
For more information about this error, try `rustc --explain E0282`.
error: could not compile `playground` due to previous error
x 传入到了 f 里,被当成闭包 f 的参数,所以类型自然应该是 T 呀!
这个闭包参数的类型需要声明,是从原理上就无法推导,还是 Rust 编译器可以改进的?
1
共 13 条评论, 1 页
评论区
写评论给不知道的人一个提醒,楼主已经在官方论坛提了同样的问题
The closure parameter type needs to be declared, can the compiler improve this?
而且我觉得那里的回答很棒了。
基本上就是 Rust 类型推断方向的事情,它当然不完美(而且规则并未被明确 —— 所以可以改进),但至少是保守的(导致的结果无非就是多加类型标注来明确你需要的类型)。
https://rustc-dev-guide.rust-lang.org/closure.html 可以看下rustc的文档
--
👇
hzqd: 我加了您说的这个trait,四种情况均无法编译,报冲突了。
但如果我只给结构体关联了同名的函数:
四种情况均能编译通过,这是为什么呢?
--
👇
wangbyby: - 对于情况四,你可以加个
看看结果.
情况3中,从
f(x)可以推出x的类型为T,但如果反过来先x.test(f),那么x的类型在此时是无法推出的,即类型推导与语句顺序有关。情况4,给结构体关联了同名的函数是指什么?
以上代码是无法通过编译的
我加了您说的这个trait,四种情况均无法编译,报冲突了。
但如果我只给结构体关联了同名的函数:
四种情况均能编译通过,这是为什么呢?
--
👇
wangbyby: - 对于情况四,你可以加个
看看结果.
看看结果.
--
👇
hzqd: 请问您如何解释以下四种编译通过的情况?
情况一:
情况二:
情况三:
情况四:
它们是如何避免“其他
trait和struct存在同名方法”而直接通过了编译呢?--
👇
Pikachu: x.test可以指向的是任意的函数。假设std或者core里有个同名的函数test,编译器不可能知道你用的是哪个函数,也就没法根据函数签名做出类型约束。
另外,对于情况三来讲,如下等价代码不能通过编译,这又是为什么?
因为
Rust具备全局类型推导的特性,它完全可以根据else代码块的内容反推x的类型。但这段代码依然获得编译错误,其故何如?
请问您如何解释以下四种编译通过的情况?
情况一:
情况二:
情况三:
情况四:
它们是如何避免“其他
trait和struct存在同名方法”而直接通过了编译呢?--
👇
Pikachu: x.test可以指向的是任意的函数。假设std或者core里有个同名的函数test,编译器不可能知道你用的是哪个函数,也就没法根据函数签名做出类型约束。
x.test可以指向的是任意的函数。假设std或者core里有个同名的函数test,编译器不可能知道你用的是哪个函数,也就没法根据函数签名做出类型约束。
如果你想明确指定这里用的是Test::test函数,你得这么写
当然这里会有warning,因为定义了一个closure但没有使用。但是最起码编译能通过,说明类型没错。
--
👇
hzqd: 但
x是闭包f的参数呀,闭包f的参数类型就是T,为何说x可以为任意类型?如果你是指:
T是泛型,而不是具体类型。那么,给x显式声明泛型T依然可以通过编译,又要如何解释?但
x是闭包f的参数呀,闭包f的参数类型就是T,为何说x可以为任意类型?如果你是指:
T是泛型,而不是具体类型。那么,给x显式声明泛型T依然可以通过编译,又要如何解释?在原错误写法中,x可以为任意类型,不一定为T类型,x的类型从原理上就无法推导。
--
👇
hzqd: 你可以解释一下为什么加上返回类型就可以通过编译吗?
你可以解释一下为什么加上返回类型就可以通过编译吗?
首先,
Pipe这个trait很奇怪,泛型参数为何不在pipe函数上而要放在trait上?这样可能更好一点。
其次,
main函数只放一个闭包表达式是什么意思?不太明白。如果只是想示意这个闭包用户,将其绑定到一个变量上,语义可能会更明确一些。
最后回到你的问题,即
|x| x.pipe(test)的类型问题。正如上面所写,那么你期望
_clousure是什么类型?如果要推导类型,只能推出来如下信息:test的类型是fn (fn (?T)).Pipe::pipe的类型中,由test为pipe的第二个参数,可知x的类型为fn (?T),x.pipe(test)的类型(即pipe中的泛型参数R)为(),|x| x.pipe(test)的类型为f(?impl Pipe)。可见,此时仍然不知道
x的类型。所以必须显式地标注x的类型。