我知道这个问题已经以不同的方式出现过很多次。但我仍然不清楚。有没有办法实现以下目标。
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
}
这是一个两步过程。 首先将 foo 转为函数,然后对其调用 tupled 使其成为元组的函数。
(foo _).tupled(getParams)
@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
最后,如果需要,您还可以进行 uncurry/untuple。
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>
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 class
es,您可以免费获得带有 apply
方法的伴生对象,因此该技术与 case class
es 一起使用更方便。
scala> case class Person(firstName: String, lastName: String)
defined class Person
scala> Person.tupled(("Rahul", "G"))
res18: Person = Person(Rahul,G)
我知道有很多代码重复,但是可惜...我们还没有宏! ;)
我很欣赏其他一些更接近您要求的答案,但我发现当前项目更容易添加另一个将元组参数转换为分割参数的函数:
def originalFunc(a: A, b: B): C = ...
def wrapperFunc(ab: (A, B)): C = (originalFunc _).tupled(ab)
现在,您可以实现 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)
对于 Scala 3。有两种选择:
foo.tupled
获取多参数函数或方法的元组版本。foo
以接受元组。多个参数会自动转换为一个元组。自动将元组应用于多参数函数在某些条件下也有效。请参阅:https://docs.scala-lang.org/scala3/reference/other-new-features/parameter-untupling.html
例如:
// a class with methods
class MyClass {
def foo(x: Int, y: Int) = println("mp")
def bar(t: (Int, Int)) = println("tp")
}
val myObject = new MyClass
val x = (1,2)
// apply to .tupled
myObject.foo.tupled(x)
// apply to bar, which already accepts a tuple
myObject.bar(x)
// Using bar, tho, both tuples and multiple arguments are accepted.
myObject.bar((3,4)) // works
myObject.bar(3,4) // also works
// If the type environment is precise enough then untupling will work as well
val xs = List(
(5,6),
(7,8)
)
xs.foreach(myObject.foo)
请注意,在 Scala 3 中不再需要将方法转换为函数的
_
。