尝试使用Xcode Playgrounds中的一系列闭包,我收到此错误:
Playground execution failed: error: closures.playground:11:25: error: ambiguous use of operator '*'
{x in x * x},
我没有从语法上看到为什么这不起作用,但应该。
我最初的关闭是:
let f = {(x: Int) -> Int
in
return x + 42}
然后我定义了一个数组:
let closures = [f,
{(x:Int) -> Int in return x * 2},
{x in return x - 8},
{x in x * x}, //This line causes the error.
{$0 * 42}]
这些闭包中的每一个都符合f
的签名,这是Xcode中的一个错误吗?如果没有,发生了什么?
对于那种情况,不应该在这种情况下推断出类型,就像在所有其他情况下明确推断的那样?
编辑:在Swift 2.2中,这似乎工作正常,但我使用的是Swift3。
答案 0 :(得分:1)
如果你愿意跟随我,我有一个理论:
使用您对f
的定义,以下行会在Swift 2.2和Swift 3.0中导致不同的错误:
let closures = [f, { $0 * 4.5 },{$0 * 42}]
注意第二个元素乘以一个Double,使x的推断类型也为Double,因此闭包签名不匹配。
在Swift 2.2中:"表达式的含义模糊,没有更多的上下文"
在Swift 3.0中:"异构收集文字只能推断为“任何”&#39 ;;如果这是故意的,请添加显式类型注释"
这似乎表明Swift 3.0编译器可以识别不同闭包签名的可能性,这些签名可以作为同质元素类型下载到Any
。
在你的例子中:
let closures = [f,
{(x:Int) -> Int in return x * 2},
{x in return x - 8},
{x in x * x}, //This line causes the error.
{$0 * 42}]
导致错误的行没有x
的显式类型。 Swift 3.0允许x
可能是其他类型的一种,例如一个Double,Float等,并且整个数组可能意图具有类型[Any]
而不是[(Int)->Int]
。因此,如果不在此位置为x
声明任何显式类型,或者为closures
整体声明任何显式类型,则编译器不清楚*
函数的哪个版本应该是选择。也许那些x
都是双打?花车?由于closures
数组的类型不明确且x
的类型不明确,因此编译器无法确定*
的哪个版本应该在那里使用以及操作数类型是什么。
因此,您可以通过使数组的类型显式来修复错误,即:
let closures:[(Int)->Int] = [f,
{(x:Int) -> Int in return x * 2},
{x in return x - 8},
{x in x * x}, //No more error.
{$0 * 42}]
或者,通过使闭包内的x
的类型明确,即:
let closures = [f,
{(x:Int) -> Int in return x * 2},
{x in return x - 8},
{(x:Int) in x * x}, //No more error.
{$0 * 42}]
在其他闭包中,与x
相对的另一个操作数足以让编译器推断出x
的类型,但是在生成错误的闭包中,没有什么能够最终确定这种类型。
同样,似乎这在Swift 2.2中有效,因为Swift 2.2不会将异构数组推断为类型[Any]
,因此假设所有闭包必须具有相同的类型。在Swift 3中,似乎允许一些模糊的可能性,这使编译器不太确定你的意图。
至少我的理论是这样的:)
答案 1 :(得分:0)