这种类型错误的原因是什么? [英] What is the cause of this type error?
问题描述
两个问题:
为什么这段代码无法编译?我相信(但不是 100% 确定,我可能犯了一个错误)它的类型是正确的.
Why does this code fail to compile? I believe (but am not 100% sure, I may have made a mistake) that it's type-correct.
错误信息是什么意思?我很困惑为什么预期的参数类型是 _ ->_
(或者我可能只是不知道在这种情况下 _ -> _
是什么意思).这个问题的目的是学习如何正确诊断此错误消息,如果我将来再次遇到它.
What does the error message mean? I'm confused why the expected argument type is _ -> _
(or maybe I just don't know what it means by _ -> _
in this case). The goal of this question is to learn how to correctly diagnosis this error message, should I run into it again in the future.
代码:
此代码无法编译并显示错误消息无法将类型 'A -> B' 的值转换为预期的参数类型 '_ -> _':
This code fails to compile with the error message "Cannot convert value of type 'A -> B' to expected argument type '_ -> _':
class ZipList<A> {
let xs: [A]
init(xs: [A]) {
self.xs = xs
}
func map<B>(f: A -> B) -> ZipList<B> {
return ZipList(xs: self.xs.map(f))
}
}
其他信息:
起初,我认为问题出在类型推断上,所以我尝试明确写出类型,但也失败了:
At first, I assumed the problem was with type inference, so I tried writing out the types explicitly, but that also failed:
然而,这编译得很好(与我原来的 map
版本的唯一区别是 <B>
传递给 ZipList
初始值设定项):
However, this compiles just fine (the only difference from my original map
version is the <B>
passed to the ZipList
initializer):
func map4<B>(f: A -> B) -> ZipList<B> {
return ZipList<B>(xs: self.xs.map(f))
}
推荐答案
问题是当你引用它时没有明确提供 ZipList
的泛型参数类型,编译器会尝试为您推断它 - 它并不总是正确.
The problem is that when you don't explicitly supply the generic parameter type of ZipList
when you refer to it, the compiler will try and infer it for you – which it doesn't always get correct.
由于您已经在 ZipList
类中,编译器将尝试将 ZipList
推断为 ZipList
当您省略通用参数时(有关此行为的更多信息,请参阅此问题).
As you're already inside a ZipList<A>
class, the compiler will try and infer ZipList
to be ZipList<A>
when you omit the generic parameter (see this question for more info about this behaviour).
因此它现在期望 ZipList(xs:_)
初始化程序中的 [A]
输入,这意味着 map 函数被推断为 A->A
,你试图通过 A ->B
到,导致类型不匹配(这就是为什么 f
在您的错误中突出显示为问题).
Therefore it's now expecting an input of [A]
in the ZipList(xs:_)
initialiser, meaning that the map function is inferred to be A -> A
, which you're trying to pass A -> B
to, causing the type mismatch (this is why f
is highlighted as the problem in your error).
如果您将示例简化为仅在 ZipList
上调用 init()
而不提供参数,您将看到更有用的错误消息:
If you simplify down your example to just calling init()
on your ZipList
without providing an argument, you'll see a more helpful error message:
class ZipList<A> {
init() {}
func map<B>() -> ZipList<B> {
// error: Cannot convert return expression of type 'ZipList<A>' to 'ZipList<B>'
return ZipList()
}
}
编译器完全忽略map()
方法返回的显式类型注释这一事实是一个错误,由SR-1789.正如 Jordan Rose 在报告评论中所描述的,原因是:
The fact that the compiler completely ignores the explicit type annotation of the return for the map()
method is a bug and is tracked by SR-1789. The cause, as described by Jordan Rose in the comments of the report is that:
这似乎是我们急切地假设参数与 self
相同的情况.(这通常是一个特征,但当它妨碍其他推理时就不是.)
It seems to be a case of us eagerly assuming the parameters are the same as for
self
. (That's usually a feature, but not when it gets in the way of other inference.)
正如您已经发现的,解决方案是在创建新实例时显式声明 ZipList
的通用参数类型:
The solution, as you've already found, is to explicitly state the generic parameter type of ZipList
when you create a new instance:
return ZipList<B>(xs: xs.map(f))
这会强制泛型参数为 B
类型,从而防止 Swift 错误地推断它,从而允许 map
函数解析.
This forces the generic parameter to be of type B
, therefore preventing Swift from incorrectly inferring it, allowing the map
function to resolve.
至于错误信息Cannot convert value of type 'A -> B' to expected argument type '_ -> _"是什么意思,_
在这个case 只是指编译器无法解析的泛型类型(我知道这不是有用的错误消息).所以编译器告诉你的只是它期待一个接受未知类型输入并返回相同类型的函数.
As for what the error message "Cannot convert value of type 'A -> B' to expected argument type '_ -> _" means, _
in this case simply refers to a generic type which the compiler cannot resolve (not a helpful error message, I know). So all the compiler is telling you is that it was expecting a function that takes an input of an unknown type, and returns that same type.
在诊断此类错误消息时,将表达式拆分为多个子表达式并检查每个子表达式的类型以尝试找出不匹配的情况通常会有所帮助.它还可以帮助开始简化示例(例如在 map
中使用 init()
而不是 init(xs:[A])
方法),直到您遇到更有用的错误消息.
It often helps when diagnosing these kind of error messages to split the expression up into multiple sub-expressions and inspect the types for each those to try and find the mis-match. It can also help to begin simplifying the example down (like using init()
instead of init(xs:[A])
in your map
method), until you run into a more helpful error message.
这篇关于这种类型错误的原因是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!