为什么我不能在带有可变参数,匿名参数的单行Swift闭包中使用.reduce()?

时间:2016-02-26 09:40:33

标签: swift

第一个封闭工作。但是,只要我取出虚拟赋值,闭包就会停止工作(addUpClosureRedFlagged)。谁知道为什么?

let addUpClosureWorking: (Int ...) -> Int = {
  let dummy = "Anything"  // Comment out and wait for the error...
  return $0.reduce(0, combine: +)
}

let addUpClosureRedFlagged: (Int ...) -> Int = {
  return $0.reduce(0, combine: +)   // Should work, but doesn't!
}


addUpClosureWorking(1, 2, 3, 4, 5) // 15

3 个答案:

答案 0 :(得分:2)

从当前的Swift(2.1)开始,当只包含一行时,闭包的类型推断可能会有点奇怪,例如, this somewhat related issue;期望在闭包中明确包含函数类型签名。

这个(编译器)" bug" /闭包限制(至少)存在于变异和inout参数:

// variadiac argument example
let fooErr1: (Int ...) -> Int = {
    return $0.reduce(0, combine: +)
} 
// or: let fooErr1: (Int ...) -> Int = { $0.reduce(0, combine: +) }
   /*  error: cannot convert value of type '(_) -> Int' 
              to specified type '(Int...) -> Int'       */

// inout argument example
let fooErr2: (inout _: Int) -> Int = {
    return $0
}
// or: let fooErr2: (inout _: Int) -> Int = { $0 } 
   /* error: cannot convert value of type '_ -> Int' 
             to specified type '(inout Int) -> Int'     */

这可以通过在闭包中显式包含函数:s类型签名,或者在return语句之前包含 any 语句来避免(因此将闭包扩展为包含多行)

/* Avoiding fooErr1:
   - explicitly state function type signature in closure    */
let foo: (Int ...) -> Int = {
    (bar: Int ...) -> Int in
    return bar.reduce(0, combine: +)
}

/* - include any kind of statment prior to return statement */
let foo2: (Int ...) -> Int = {
    (); return $0.reduce(0, combine: +)
}

/* Avoiding fooErr2:
   - explicitly state function type signature in closure    */
let foo3: (inout _: Int) -> Int = {
    (inout bar: Int) -> Int in 
    return bar
}

/* - include any kind of statment prior to return statement */
let foo4: (inout _: Int) -> Int = {
    (); return $0
}

为什么呢?我写过" bug"上面,但也许是编译器对闭包类型推断的当前限制;正如Pradeep K在他的回答中所写,这很可能是由于Swift编译器的一些复杂性,在这些情况下失败的类型推断。

答案 1 :(得分:1)

这可能是因为编译器在处理一个行闭包时所做的一些优化。如果您根据其类型显式接受闭包参数,那么您不需要虚拟线。

let addUpClosureRedFlagged: (Int ...) -> Int = {
    (arr:Int...) -> Int in
    return arr.reduce(0, combine: +)
}

更多关于如何处理一个行闭包。

例如这个闭包的类型是() - >诠释。由于它是一行闭包,因此该行的返回值被视为闭包的返回值,在这种情况下为Int。因为它不带任何args它是()。因此类型是() - > Int

let addEvens = {
    [2,4,6,8].reduce(0, combine: +)
}

但是一旦添加虚拟线,它就变成了类型() - > (),一个不接受任何参数但不返回任何值的闭包。

let addEvens = {
    let dummy = 100
    [2,4,6,8].reduce(0, combine: +)
}

在你的情况下,一行闭包是类型(_) - > Int而类型是(Int ...) - > Int你可以通过不明确定义一行闭包的类型来解决这个问题允许编译器推断出类型。

let addUpClosureRedFlagged = {
    (arr:Int...) -> Int in
    return arr.reduce(0, combine: +)
}

答案 2 :(得分:0)

可能是编译器错误。提起雷达?

因为你的所有参数都是相同类型的,所以你也可以使用[Int]个参数:

let sumArray: ([Int]) -> Int = {
    return $0.reduce(0, combine: +)
}

sumArray([1, 2, 3, 4, 5])会返回正确的结果。