giải nén scala tuple


91

Tôi biết câu hỏi này đã được đưa ra nhiều lần theo nhiều cách khác nhau. Nhưng nó vẫn không rõ ràng với tôi. Có cách nào để đạt được những điều sau đây.

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
Điều gì sẽ xảy ra nếu foo là hàm tạo của một số lớp?
scout

Câu trả lời:


107

Đó là một quy trình hai bước. Đầu tiên, biến foo thành một hàm, sau đó gọi bộ giá trị trên nó để biến nó thành một hàm của một bộ giá trị.

(foo _).tupled(getParams)

3
Sẽ không rõ ràng hơn nếu Scala chỉ nghĩ về các đối số như Tuples để bắt đầu?
Câu chuyện của Henry

12
Vâng, sẽ gọn gàng hơn rất nhiều nếu Scala thống nhất việc xử lý các bộ giá trị và danh sách đối số. Từ những gì tôi đã nghe, có rất nhiều trường hợp không rõ ràng sẽ cần được xử lý cẩn thận để điều đó xảy ra. Theo như tôi biết, việc thống nhất các bộ giá trị và danh sách đối số không có trong lộ trình Scala vào lúc này.
Dave Griffith

2
Chỉ cần thêm, nếu foo là phương pháp nhà máy của đối tượng bạn đồng hành, người ta có thể sử dụng (Foo.apply _) tupled (getParams).
RAbraham

55

@ dave-griffith đã chết.

Bạn cũng có thể gọi:

Function.tupled(foo _)

Nếu bạn muốn đi lang thang trong lãnh thổ "nhiều thông tin hơn tôi yêu cầu", thì cũng có các phương pháp được tích hợp trong các chức năng được áp dụng một phần (và bật Function) cho cà ri. Một số ví dụ đầu vào / đầu ra:

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>

Trong đó phiên bản cà ri được gọi với nhiều danh sách đối số:

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

Cuối cùng, bạn cũng có thể gỡ rối / gỡ rối nếu cần. Functioncó nội trang cho điều này:

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)hoặc một trong những gợi ý của Dave.

BIÊN TẬP:

Để trả lời bình luận của bạn:

Điều gì sẽ xảy ra nếu foo là hàm tạo của một số lớp?

Trong trường hợp đó, thủ thuật này sẽ không hoạt động.

Bạn có thể viết một phương thức gốc trong đối tượng đồng hành của lớp của mình và sau đó lấy phiên bản bộ của applyphương thức đó bằng một trong các kỹ thuật đã nói ở trên.

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

Với case classes, bạn nhận được một đối tượng đồng hành với một applyphương thức miễn phí, và do đó kỹ thuật này thuận tiện hơn khi sử dụng với case classes.

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

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

Tôi biết đó là rất nhiều mã trùng lặp nhưng than ôi ... chúng tôi chưa có macro (chưa)! ;)


3
Trong ví dụ cuối cùng ở đây, bạn có thể cắt bỏ một chút ... Các đối tượng đồng hành cho các lớp trường hợp luôn mở rộng đặc điểm FunctionN thích hợp. Vì vậy, dòng cuối cùng có thể là Person.tupled(("Rahul", "G")) Thật tiện lợi khi làm điều này trong các đối tượng đồng hành được viết tay.
David Winslow

3

Tôi đánh giá cao một số câu trả lời khác gần hơn với những gì bạn yêu cầu, nhưng tôi thấy dự án hiện tại dễ dàng hơn khi thêm một hàm khác chuyển đổi tham số tuple thành tham số tách:

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

1

Bây giờ, bạn có thể triển khai foo và biến nó thành một tham số của lớp Tuple2 như vậy.

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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.