Scala tuple แกะกล่อง


95

ฉันรู้ว่าคำถามนี้เกิดขึ้นหลายครั้งในรูปแบบต่างๆ แต่มันก็ยังไม่ชัดเจนสำหรับฉัน มีวิธีที่จะบรรลุดังต่อไปนี้

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 เป็นตัวสร้างของคลาสบางคลาส?
scout

อาจซ้ำกันได้ของHow to use a function to a tuple?
สุมา

คำตอบ:


107

เป็นขั้นตอนสองขั้นตอน ก่อนอื่นให้เปลี่ยน foo ให้เป็นฟังก์ชันจากนั้นเรียก tupled เพื่อทำให้เป็นฟังก์ชันของ tuple

(foo _).tupled(getParams)

3
มันจะไม่สะอาดกว่านี้หรือถ้า Scala คิดว่าจะเริ่มต้นด้วยการโต้เถียงเป็น Tuples
Henry Story

12
ใช่มันจะสะอาดกว่านี้มากถ้า Scala จะรวมการจัดการสิ่งที่เพิ่มขึ้นและรายการอาร์กิวเมนต์ จากสิ่งที่ฉันได้ยินมามีกรณีขอบที่ไม่ชัดเจนจำนวนมากที่ต้องใช้ความระมัดระวังเพื่อให้เกิดขึ้น เท่าที่ฉันทราบการรวมรายการสิ่งที่เพิ่มขึ้นและรายการอาร์กิวเมนต์ไม่ได้อยู่ในแผนงานของ Scala ในขณะนี้
Dave Griffith

2
หากต้องการเพิ่มถ้า foo เป็นวิธีการโรงงานของอ็อบเจ็กต์ที่แสดงร่วมกันก็สามารถใช้ (Foo.apply _) tupled (getParams)
RAbraham

56

@ 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>

โดยเวอร์ชัน curried จะถูกเรียกใช้ด้วยรายการอาร์กิวเมนต์หลายรายการ:

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.