scala tuple desempacando
parameters tuples (5)
Sé que esta pregunta ha surgido muchas veces de diferentes maneras. Pero todavía no está claro para mí. ¿Hay alguna manera de lograr lo siguiente?
def foo(a:Int, b:Int) = {}
foo(a,b) //right way to invoke foo
foo(getParams) // is there a way to get this working without explicitly unpacking the tuple??
def getParams = {
//Some calculations
(a,b) //where a & b are Int
}
@ dave-griffith está muerto.
También puedes llamar:
Function.tupled(foo _)
Si quieres adentrarte en "mucho más información de la que pedí" territorio, también hay métodos integrados en funciones parcialmente aplicadas (y en Function
) para currying. Algunos ejemplos de entrada / salida:
scala> def foo(x: Int, y: Double) = x * y
foo: (x: Int,y: Double)Double
scala> foo _
res0: (Int, Double) => Double = <function2>
scala> foo _ tupled
res1: ((Int, Double)) => Double = <function1>
scala> foo _ curried
res2: (Int) => (Double) => Double = <function1>
scala> Function.tupled(foo _)
res3: ((Int, Double)) => Double = <function1>
// Function.curried is deprecated
scala> Function.curried(foo _)
warning: there were deprecation warnings; re-run with -deprecation for details
res6: (Int) => (Double) => Double = <function1>
Donde se invoca la versión curried con múltiples listas de argumentos:
scala> val c = foo _ curried
c: (Int) => (Double) => Double = <function1>
scala> c(5)
res13: (Double) => Double = <function1>
scala> c(5)(10)
res14: Double = 50.0
Finalmente, también puede desajustar / destrabar si es necesario. Function
tiene edificaciones integradas para esto:
scala> val f = foo _ tupled
f: ((Int, Double)) => Double = <function1>
scala> val c = foo _ curried
c: (Int) => (Double) => Double = <function1>
scala> Function.uncurried(c)
res9: (Int, Double) => Double = <function2>
scala> Function.untupled(f)
res12: (Int, Double) => Double = <function2>
Ahora, puedes implementar foo y hacerlo tomar un parámetro de la clase Tuple2 como tal.
def foo(t: Tuple2[Int, Int]) = {
println("Hello " + t._1 + t._2)
"Makes no sense but ok!"
}
def getParams = {
//Some calculations
val a = 1;
val b = 2;
(a, b) //where a & b are Int
}
// So you can do this!
foo(getParams)
// With that said, you can also do this!
foo(1, 3)
Aprecio algunas de las otras respuestas que estaban más cerca de lo que pediste, pero me resultó más fácil para un proyecto actual agregar otra función que convierta los parámetros de tupla en los parámetros de división:
def originalFunc(a: A, b: B): C = ...
def wrapperFunc(ab: (A, B)): C = (originalFunc _).tupled(ab)
Es un procedimiento de dos pasos. Primero convierte foo en una función, luego llama a tupled para que sea una función de una tupla.
(foo _).tupled(getParams)
Function.tupled(foo _)(getParams)
o el sugerido por Dave.
EDITAR:
Para responder a tu comentario:
¿Qué pasa si foo resulta ser el constructor de alguna clase?
En ese caso, este truco no funcionará.
Puede escribir un método de fábrica en el objeto complementario de su clase y luego obtener la versión en tupla de su método de apply
utilizando una de las técnicas antes mencionadas.
scala> class Person(firstName: String, lastName: String) {
| override def toString = firstName + " " + lastName
| }
defined class Person
scala> object Person {
| def apply(firstName: String, lastName: String) = new Person(firstName, lastName)
| }
defined module Person
scala> (Person.apply _).tupled(("Rahul", "G"))
res17: Person = Rahul G
Con las case class
obtienes un objeto complementario con un método de apply
forma gratuita, y por lo tanto, esta técnica es más conveniente de usar con case class
.
scala> case class Person(firstName: String, lastName: String)
defined class Person
scala> Person.tupled(("Rahul", "G"))
res18: Person = Person(Rahul,G)
Sé que es mucha duplicación de código, pero lamentablemente ... ¡todavía no tenemos macros! ;)