Swift不能从上下文推断类型

时间:2014-09-22 17:59:28

标签: swift

我有一个看似合法的函数,可以将数组转换为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 })

它运作得很好。为什么呢?

1 个答案:

答案 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 })