Swift Closures不作任何输入

时间:2015-09-01 07:42:35

标签: swift

以下(工作)代码创建一个UIAlertAction,在按下按钮ok后调用函数foo()。

let action = UIAlertAction(title: "OK", style: .Default, handler: {action in self.foo()})

我的问题是为什么必须将动作传递给闭包?

例如,这样的事情对我有意义,因为我们在闭包中根本没有引用动作。我希望能写出像

这样的东西
{ () in self.foo() }

{ self in self.foo() }

在C ++中,我希望写出像

这样的东西
[this](){this->foo();};

这是怎么回事?

3 个答案:

答案 0 :(得分:3)

如果编译器可以确定闭包的类型,则可以使用隐式返回和速记参数名称,从而声明闭包,如:

let sorted = [ 4, 3, 1, 40, 19 ].sort { $0 > $1 }

但是,如果编译器无法确定它,则需要声明参数以便确定。

以您自己的代码为例:

class Bar {

  func foo() {
  }

  func foo( s: String ) {
  }

  func sample() {
    // this works
    let a = UIAlertAction(title: "a", style: .Default, handler: { self.foo($0.title) } )
    // this doesn't work
    let a = UIAlertAction(title: "a", style: .Default, handler: { self.foo() } )
  }
}

处理程序闭包有((UIAlertAction!) - >(Void))!的定义,所以它期望一个带有单个参数的闭包(推断出类型为UIAlertAction)并且它什么也不返回。

第一个例子有效,因为通过使用$ 0你告诉编译器闭包实际上有一个参数,并且由于最后一次调用是函数foo而没有返回任何内容,你的闭包有一个参数并且什么都不返回,所以编译器可以这样使用它。

但是,第二个不起作用,因为即使foo没有返回任何内容,你也不会使用任何参数,因此编译器无法判断你的闭包是否有参数。对于编译器,你的闭包是:( Void) - >(Void),它不是正确的类型。

如果你的foo函数或闭包定义不允许编译器检测闭包类型,那么ABakerSmith可能就是你需要的答案。您仍然需要声明参数,但忽略它们将是最佳的操作过程:

let a = UIAlertAction(title: "a", style: .Default, handler: { _ in self.foo() } )

答案 1 :(得分:2)

您可以使用下划线忽略传递给处理程序闭包的参数,从而生成代码:

{ _ in self.foo() }

你可以使用下划线来忽略其他情况下的参数,例如for循环:

for _ in 0..<5 {
    ...
}

答案 2 :(得分:1)

@ ncerzo的回答是正确的 - 这只是澄清了一些事情。与Swift中的其他所有内容一样,闭包有一个类型,编译器不会编译,直到它可以确认您传递的闭包类型与所需类型匹配。编译器尽力从上下文中推断出闭包的类型,但有时候它不能并且它要求代码是特定的。

你所说的闭包只是忽略了传递的参数。一个非常简单的例子是一个看起来像这样的闭包:

let ignoreMe: Int -> Int = { _ in 42 }

无论您传递给ignoreMe的参数是什么,它都会被忽略,返回的值将为42。所以你似乎在问为什么下划线是必要的。你想写这个:

let ignoreMe: Int -> Int = { 42 }

问题是编译器无法将右侧的类型与左侧的类型相匹配。结束{ 42 } 推断的类型为Void -> Int,而左侧的ignoreMe则声明类型为Int -> Int。这些类型不匹配。

错误是编译器告诉你的方式,&#34;我期待类型为Int -> Int的闭包,但你似乎给了我Void -> Int类型的闭包。请澄清你的意图。&#34;

{ _ in 42 }中的下划线是您如何提供澄清。你告诉编译器,&#34;是的,这个闭包将采取一个参数,但它将被忽略。您可以安全地将其类型推断为Int -> Int。&#34;

要求这种澄清似乎是不必要的包袱,但行李很轻。 { 42 }{ _ in 42 }对编码员的负担不是很大。而且好处是巨大的。对于左侧类型和右侧类型之间的每个故意不匹配,必定存在大量无意的不匹配(也就是错误或错误)。在代码编译之前,必须修复那些无意的不匹配。