scala tuple paketini açma


95

Bu sorunun birçok kez farklı şekillerde ortaya çıktığını biliyorum. Ama benim için hala net değil. Aşağıdakileri elde etmenin bir yolu var mı?

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
Ya foo bir sınıfın kurucusu olursa?
izci

Yanıtlar:


107

Bu iki aşamalı bir prosedür. Önce foo'yu bir işleve çevirin, ardından onu bir demetin işlevi yapmak için tupled'i çağırın.

(foo _).tupled(getParams)

3
Scala argümanları başlangıçta Tuples olarak düşünseydi daha temiz olmaz mıydı?
Henry Story

12
Evet, Scala tuple ve argüman listelerini işlemeyi birleştirirse çok daha temiz olurdu. Duyduğuma göre, bunun gerçekleşmesi için dikkatli bir şekilde ele alınması gereken birçok bariz olmayan uç durum var. Bildiğim kadarıyla, tuple'ların ve argüman listelerinin birleştirilmesi şu anda Scala yol haritasında yer almıyor.
Dave Griffith

2
Tamamlayıcı nesnenin fabrika yöntemi foo ise, eklemek için (Foo.apply _). Tupled (getParams)
RAbraham

56

@ dave-griffith öldü.

Ayrıca şunları da arayabilirsiniz:

Function.tupled(foo _)

"Benim istediğimden çok daha fazla bilgi" alanına girmek istiyorsanız, körleme için kısmen uygulanan (ve açık Function) işlevlere yerleşik yöntemler de vardır . Birkaç girdi / çıktı örneği:

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>

Burada curried versiyonu birden fazla argüman listesiyle çağrılır:

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

Son olarak, gerekirse curry / unuple da yapabilirsiniz. Functionbunun için yerleşikler var:

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)ya da Dave tarafından önerilen.

DÜZENLE:

Yorumunuza cevap vermek için:

Ya foo bir sınıfın kurucusu olursa?

Bu durumda, bu numara işe yaramayacaktır.

Sınıfınızın tamamlayıcı nesnesine bir fabrika yöntemi yazabilir ve ardından applyyukarıda belirtilen tekniklerden birini kullanarak yönteminin tupled sürümünü elde edebilirsiniz .

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

İle case classes bir olan bir arkadaşı nesneyi almak applyücretsiz yöntemle ve böylece bu teknik ile kullanmak için daha uygun olur case classes.

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

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

Bunun çok fazla kod kopyası olduğunu biliyorum ama ne yazık ki ... (henüz) makrolarımız yok! ;)


3
Buradaki son örnekte, biraz ... Vaka sınıfları için tamamlayıcı nesneler her zaman uygun FunctionN özelliğini genişletir. Bu yüzden son satır, Person.tupled(("Rahul", "G")) bunu elle yazılmış yardımcı nesnelerde de yapmak kullanışlı olabilir .
David Winslow

3

İstediğinize daha yakın olan diğer cevaplardan bazılarını takdir ediyorum, ancak mevcut bir projenin tuple parametrelerini bölünmüş parametrelere dönüştüren başka bir işlev eklemesini daha kolay buldum:

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

1

Şimdi, foo uygulayabilir ve bunun Tuple2 sınıfının bir parametresini almasını sağlayabilirsiniz.

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)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.