两个问题:
为什么这段代码编译失败?我相信(但不是 100% 肯定,我可能犯了一个错误)它的类型是正确的。
错误信息是什么意思?我很困惑为什么预期的参数类型是
_ -> _
(或者也许我只是不知道在这种情况下_ -> _
是什么意思)。这道题的目的是学习如何正确诊断这个错误信息,如果我以后再遇到它。
代码:
此代码无法编译并显示错误消息“无法将类型 'A -> B' 的值转换为预期的参数类型 '_ -> _':
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))
}
}
附加信息:
起初,我认为问题出在类型推断上,所以我尝试显式写出类型,但也失败了:
然而,这编译得很好(与我原来的 map
版本的唯一区别是 <B>
传递给 ZipList
初始化程序):
func map4<B>(f: A -> B) -> ZipList<B> {
return ZipList<B>(xs: self.xs.map(f))
}
最佳答案
问题是当您没有显式提供 ZipList
的通用参数类型时当您引用它时,编译器会尝试为您推断它——它并不总是是正确的。
因为您已经在 ZipList<A>
中了类,编译器将尝试推断 ZipList
成为ZipList<A>
当您省略通用参数时(有关此行为的更多信息,请参阅 this question)。
因此它现在期望输入 [A]
在ZipList(xs:_)
初始化程序,意味着映射函数被推断为 A -> A
,你正试图通过 A -> B
到,导致类型不匹配(这就是为什么 f
在您的错误中突出显示为问题)。
如果您将示例简化为只调用 init()
在你的 ZipList
在不提供参数的情况下,您会看到更有用的错误消息:
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 在报告的评论中所描述的那样,原因是:
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
的通用参数类型当您创建一个新实例时:
return ZipList<B>(xs: xs.map(f))
这强制通用参数的类型为 B
,因此防止 Swift 错误地推断它,允许 map
功能来解决。
至于错误消息“无法将类型 'A -> B' 的值转换为预期参数类型 '_ -> _”的含义,_
在这种情况下,它只是指编译器无法解析的泛型类型(我知道这不是有用的错误消息)。因此,所有编译器都在告诉您,它期待一个接受未知类型输入并返回相同类型的函数。
在诊断此类错误消息时,将表达式拆分为多个子表达式并检查每个子表达式的类型以尝试找到不匹配项通常会有所帮助。它还有助于开始简化示例(例如在您的 init()
方法中使用 init(xs:[A])
而不是 map
),直到您遇到更有帮助的错误消息。
关于swift - 这种类型错误的原因是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37862276/