scalaタプルの解凍


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が何らかのクラスのコンストラクタである場合はどうなりますか?
偵察

回答:


107

これは2ステップの手順です。最初にfooを関数にしてから、それにtupledを呼び出して、それをタプルの関数にします。

(foo _).tupled(getParams)

3
Scalaが引数を最初にタプルと見なすとすっきりしませんか?
ヘンリーストーリー

12
はい、Scalaがタプルと引数リストの処理を統合すると、よりクリーンになります。私が聞いたことから、それを実現するために注意深い処理を必要とする明らかでないエッジケースがたくさんあります。私の知る限り、タプルと引数リストの統合は現時点ではScalaロードマップに含まれていません。
デイブグリフィス

2
追加するだけで、fooがコンパニオンオブジェクトのファクトリメソッドである場合、(Foo.apply _)。tupled(getParams)を使用できます
RAbraham

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)

それはコードの重複が多いことを知っていますが、悲しいかな...(まだ)マクロはありません!;)


3
ここの最後の例では、少し削ることができます...ケースクラスのコンパニオンオブジェクトは、常に適切なFunctionNトレイトを拡張します。したがって、最後の行は次のようになり Person.tupled(("Rahul", "G")) ます。手書きのコンパニオンオブジェクトでもこれを行うと便利です。
David Winslow、

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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.