标量元组拆包


91

我知道这个问题已经以不同的方式提出了很多次。但是我仍然不清楚。有没有办法实现以下目标。

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
}

11
如果foo恰好是某个类的构造函数怎么办?
童军

Answers:


107

这是一个两步过程。首先将foo转换为函数,然后在其上调用tupled以使其成为元组的函数。

(foo _).tupled(getParams)

3
如果Scala只是以争论为元组开始,这会更干净吗?
亨利故事

12
是的,如果Scala统一其对元组和参数列表的处理,将会更加干净。据我了解,有很多非显而易见的边缘案例需要仔细处理才能实现。据我所知,Scala路线图上目前还没有元组和参数列表的统一。
戴夫·格里菲斯

2
只需添加一下,如果foo是伴随对象的工厂方法,则可以使用(Foo.apply _)。tupled(getParams)
RAbraham 2013年

55

@ dave-griffith死了。

您也可以致电:

Function.tupled(foo _)

如果您想进入“获取比我要的信息更多的信息”领域,则还可以在部分应用的函数(及更高版本)中内置一些用于计算的方法Function。一些输入/输出示例:

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>

其中,使用多个参数列表调用咖喱版本:

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

最后,如果需要,您还可以取消/取消订阅。 Function具有内置功能:

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>


20

Function.tupled(foo _)(getParams)或戴夫建议的那个。

编辑:

回应您的评论:

如果foo恰好是某个类的构造函数怎么办?

在这种情况下,此技巧将无效。

您可以在类的伴随对象中编写工厂方法,然后apply使用上述技术之一获取其方法的元组版本。

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

使用case classes,您可以apply免费获得带有方法的伴随对象,因此,此技术与case classes 一起使用更方便。

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

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

我知道很多代码重复,但是a……我们还没有宏!;)


3
在这里的最后一个示例中,您可以省去一点……案例类的伴侣对象始终会扩展适当的FunctionN特性。因此,最后一行可能是Person.tupled(("Rahul", "G")) 在手写伴侣对象中执行此操作也很 方便。
戴维·温斯洛

3

我很欣赏其他一些更接近您要求的答案,但我发现当前项目更容易添加另一个将元组参数转换为拆分参数的函数:

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

1

现在,您可以实现foo并使其像这样使用Tuple2类的参数。

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)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.