我有一个看似合法的函数,可以将数组转换为Dictionary:
func arrayToDictionary<Key : Hashable, Value>
(source: Array<Value>, key: Value -> Key) -> Dictionary<Key, Value> {
var dictionary = Dictionary<Key, Value>()
for element in source {
let key = key(element)
dictionary[key] = element
}
return dictionary
}
现在,当我试着打电话时:
let dict = arrayToDictionary([1, 2, 3], { val in return val })
我收到错误 - 无法转换表达式的类型'($ T6,(($ T9) - &gt;($ T9) - &gt; $ T8) - &gt;(($ T9) - &gt; $ T8) - &gt; $ T8)'输入'Hashable'
奇怪的是,如果我使用隐式回报:
let dict = arrayToDictionary([1, 2, 3], { val in val })
或简写:
let dict = arrayToDictionary([1, 2, 3], { $0 })
它运作得很好。为什么呢?
答案 0 :(得分:2)
这个问题只能由Apple的编译工程师真正回答,根据上述评论者,它可能/应该被视为一个错误,但它绝对是他们的速记语法中的漏洞。对于这样的问题,我从发布到devforums获得了很好的结果。
简单的规则是,只要有多行/需要使用return
关键字,就必须明确定义返回类型或捕获的值的类型。这种限制可能是因为在紧凑/退化的情况下,您保证只有一个退出点 - val in val
,在使用return
关键字的情况下,可以有多个回报点。在后一种情况下,您可以在一行return 1
上返回Int,并在另一行上返回nil
。在这种情况下,让编译器抱怨使假设明确是合理的。简而言之,这需要在编译器中进行更复杂的类型推断,而他们可能还没有达到这一点。
所以TL; DR,我同意将此报告为bug的建议,同时,从闭包中指定一个返回类型。尽管编译器有足够的上下文来推断正确的类型,但仍然如上所述。
请注意,除了您的示例之外,这些案例也有效:
// inferring var dict as a context for lines below
var dict = arrayToDictionary([1, 2, 3], { val in val })
// dict is already defined, so this works:
dict = arrayToDictionary([1, 2, 3], { val in return val })
// explicit final type, compiler infers backwards
let d2:Dictionary<Int, Int> = arrayToDictionary([1, 2, 3], { val in val })
// explicit return type, compiler infers "forewards"
let d3 = arrayToDictionary([1, 2, 3], { val -> Int in return val })