¿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.
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
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 aInt
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 .