Scala 元组解压缩

我知道这个问题以不同的方式出现过很多次。但我还是不清楚。有没有办法实现以下目标。

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
}
39427 次浏览

It's a two step procedure. First turn foo into a function, then call tupled on it to make it a function of a tuple.

(foo _).tupled(getParams)

Function.tupled(foo _)(getParams) or the one suggested by Dave.

EDIT:

To respond to your comment:

What if foo happens to be the constructor of some class?

In that case, this trick won't work.

You can write a factory method in the companion object of your class and then obtain the tupled version of its apply method using one of the aforementioned techniques.

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

With case classes you get a companion object with an apply method for free, and thus this technique is more convenient to use with case classes.

scala> case class Person(firstName: String, lastName: String)
defined class Person


scala> Person.tupled(("Rahul", "G"))
res18: Person = Person(Rahul,G)

I know that's a lot of code duplication but alas... we don't have macros (yet)! ;)

@dave-griffith is dead on.

You can also call:

Function.tupled(foo _)

If you want to wander into "way more information than I asked for" territory, there are also methods built into partially applied functions (and on Function) for currying. A few input/output examples:

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>

Wherein the curried version is invoked with multiple argument lists:

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

Finally, you can also uncurry/untuple if needed. Function has builtins for this:

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>

Now, you can implement foo and make it take a param of the Tuple2 class like so.

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)

I appreciate some of the other answers which were closer to what you asked for, but I found it easier for a current project to add another function which converts tuple parameters into the split parameters:

def originalFunc(a: A, b: B): C = ...
def wrapperFunc(ab: (A, B)): C = (originalFunc _).tupled(ab)