swift closures variadic-functions swift2.2

¿Cómo usar un cierre variadic en swift?



closures variadic-functions (1)

¿Hay una forma adecuada de usar una lista de parámetros variados en un cierre en Swift?

Rápidamente noté que puedo declarar una función que toma una lista de argumentos variados como tal

protocol NumberType: Comparable, IntegerLiteralConvertible, IntegerArithmeticType {} extension Int: NumberType {} extension SequenceType where Generator.Element: NumberType { func satisfy(closure:(args: Generator.Element...) -> ()) { // Do something closure(args: 1, 2, 3) } }

Que compila bien Cuando trato de usar la función:

[1, 2].satisfy { (args) in print (args) }

Xcode logra autocompletarse como era de esperar, pero inmediatamente después de cerrar el paréntesis después de args, todo el resaltado de sintaxis en Xcode desaparece y veo un mensaje "Command failed due to signal: Segmentation Fault: 11" , que parece significar que Xcode es súper confundido

Para el contexto, había planeado ver si Swift podía escribir una función que pudiera devolver respuestas basadas en un número variable de parámetros (mapeo al número de bucles for necesarios para obtener una respuesta de fuerza bruta). Sería una manera simple de probar la respuesta a una pregunta como "Dado un conjunto de Ints, encuentre todas las combinaciones que satisfagan la ecuación a ^ 3 + b ^ 3 = c ^ 3 + d ^ 3" con

let answer = array.satisfy ({ return pow($0, 3) + pow($1, 3) == pow($2, 3) + pow($3, 3) })

contra una solución más óptima.

"Devolver todos los 2" sería solo

let answer = array.satisfy ({ return $0 == 2 })

Un solo bucle


Limitación / error del compilador con inferencia de tipo de argumento para cierres de una sola expresión

Creo que la fuente de esto es una limitación (/ error) actual en el compilador que permite inferir los tipos de argumentos en los cierres de línea única utilizando parámetros variados, véase, por ejemplo, las siguientes preguntas y respuestas.

  1. ¿Por qué no puedo usar .reduce () en un cierre Swift de una sola línea con un argumento anónimo y varónico?

Un problema similar también estuvo presente para los argumentos inout en Swift 2.1 (pero ya no en 2.2), como se explica en el siguiente hilo

  1. Inline if declaración mutación inout parámetro en un cierre de retorno void, error extraño (Error: tipo ''Int1'' no se ajusta al protocolo ''BooleanType'')

Sin embargo, al mirar el hilo 1. y al intentar encontrar el error descrito marcado en Swift JIRA , parece como si el OP del hilo 1. nunca hubiera presentado un error para esto, después de todo. Es posible que no haya encontrado un informe de fallas existente, pero si no existe, posiblemente se deba archivar.

Soluciones actuales

Posibles soluciones temporales, hasta que la inferencia de tipo de argumento de cierre del compilador alcance

  • Extienda el cierre más allá del cuerpo de una sola línea

    // ... [1, 2].satisfy { (args) in () // dummy print (args) // [1, 2, 3] }

  • O bien, incluir explícitamente el tipo de args , por ej.

    [1, 2].satisfy { (args: Int...) in print (args) // [1, 2, 3] }

    Tenga en cuenta que Generator.Element resuelve a Int en este ejemplo anterior.

Estado actual de Swift 3.0-dev

Como se mencionó brevemente arriba, curiosamente, este error

  • inout: aparentemente ya no está presente en Swift 2.2 o Swift 3.0-dev para los argumentos inout , como se describe en Q & A 2. como se relacionó anteriormente

    • posiblemente se corrigió porque se resolvió el error [SR-7] (-> Swift 2.2)
    • sin embargo, parece ser la regresión 2.2-> 3.0-dev, inferencia de tipo wrt para los argumentos inout , como se informa en el informe de errores [SR-892] . Por ejemplo, el siguiente fragmento funciona en Swift 2.2, pero no en 3.0-dev (snipper mínimamente modificado del informe de error [SR-7])

      func f(inout a: Int) {} let g = { x in f(&x) } // OK 2.2, crashes 3.0-dev

  • variadic: todavía está presente en Swift 2.2 así como en Swift 3.0-dev para argumentos variados (este hilo y Q & A 1. arriba ).

    • un ejemplo más condensado del error:

      let a: (Int...) -> () = { (args) in print(args) } // bug: crashes let b: (Int...) -> () = { (args: Int...) in print(args) } // explicitly state argument type, OK let c: (Int...) -> () = { (args) in (); print(args) } // extend to more than single line closure, OK

(Para Swift 3.0-dev, probado usando IBM Swift Sandbox ejecutando Swift 3.0-dev .