仅访问匿名闭包参数的子集

时间:2016-05-27 20:04:10

标签: swift swift2

我在理解匿名闭包参数的使用方面遇到了一些麻烦。为了说明我在操场上掀起了这个人为的例子:

typealias SomeClosureType = (
thing0: Float,
thing1: Float,
thing2: Float,
thing3: Float,
thing4: Float,
thing5: Float
) -> Void

class MyClass {

    var someClosure: SomeClosureType!

    init() {
        // This is OK but long
        self.someClosure = { (thing0: Float, thing1: Float, thing2: Float, thing3: Float, thing4: Float, thing5: Float) in self.handleThing0(thing0) }

        // Compiler error: "cannot assign value of type '(Float) -> ()' to type 'SomeClosureType!'"
        self.someClosure = { self.handleThing0($0) }
    }

    func handleThing0(thing0: Float) {
        print("\(thing0)")
    }
}

let myInstance = MyClass()
myInstance.someClosure(thing0: 0, thing1: 1, thing2: 2, thing3: 3, thing4: 4, thing5: 5)

所以基本上当我尝试从闭包中访问匿名闭包参数时,我得到了这个错误。我错过了什么?

4 个答案:

答案 0 :(得分:3)

对于编译器来说,看起来你的闭包只处理一个float参数,因为你的闭包永远不会以任何方式引用其他5个“东西”。因此存在明显的不匹配,并且编译器将其标记为错误。

如果以任何有效方式引用所有6个输入参数,则错误将消失。例如,虽然这不是你应该写的东西,但仅仅引用这样的附加参数是有效的:

self.someClosure = { self.handleThing0($0); _ = [$1,$2,$3,$4,$5] }

表达目标的最短/最佳方式是:

self.someClosure = { thing0, _, _, _, _, _ in self.handleThing0(thing0) }

其中每个_表示您忽略的值,但编译器可以推断它们将是Float值。

答案 1 :(得分:2)

这个具体问题会定期出现在迅速演变中。克里斯拉特纳说this is considered a bug in the compiler, but it requires significant effort to fix

  

2016年5月13日上午9:16,Joe Groff通过快速进化    swift.org>写道:

     
    
      

这鼓励在可选的封闭物上使用空的封闭物,我认为这是有争议的。一般来说,我尽量避免选择       当它们可以用非可选值精确替换时。       此外,大多数Cocoa完成处理程序都不是可选的。

             

另一种方法是不这样做,但鼓励任何合理地为空的闭包实际上都是可选的。我会       然后想要导入带有void返回闭包的Cocoa函数       作为避免“{_ in}”的选项。

    
         

1。一般来说,我认为我们应该允许隐式参数,而不要求闭包像我们一样使用所有隐式$ n变量     今天。这些都应该是有效的:

         

let _: () -> () = {}
    let _: (Int) -> () = {}
    let _: (Int, Int) -> Int = { 5 }
    let _: (Int, Int) -> Int = { $0 }
    let _: (Int, Int) -> Int = { $1 }

  
     

我同意,但我认为这是编译器中的一个明显错误。一世   不认为它需要一个提案。

     

不幸的是,修复它是非常重要的......

     

-Chris

在修复发生之前,你会遇到第一个表单。

答案 2 :(得分:0)

我不是100%肯定你在这里想做什么,但我会试着提供一些信息。对于顶部(长的),这实际上是正确的。所以闭包只是真正的功能,设计得更紧凑,就像你当前范围内的小块代码一样。如果您只打算使用thing0属性,那么您可以使用_忽略其余部分,例如:

self.someClosure = { thing0, _ in
   self.handleThing0(thing0)
}

虽然使用闭包时需要小心,因为ARC很容易开始获得保留周期。

答案 3 :(得分:0)

在你的第二个闭包中你只使用$0所以编译器假设你的匿名闭包只需要一个参数,考虑到handleThing0()(Float) -> ()的签名,然后编译器知道封闭的签名是(Float) -> (),因为$0被传递给handleThing0(),但不返回任何内容。

然后尝试将(Float) -> ()闭包分配给类型为(Float, Float, Float, Float, Float, Float) -> Void的属性,这是不可能的,因为闭包采用小于请求的5参数,因此出错。