Создание класса дела из списка параметров - PullRequest
40 голосов
/ 27 ноября 2010

Дано:

case class Foo(a: Int, b: String, c: Double)

Вы можете сказать:

val params = Foo(1, "bar", 3.14).productIterator.toList

и получить:

params: List[Any] = List(1, bar, 3.14)

Есть ли способ «вернуться назад» и воссоздатьобъект Foo непосредственно из этого списка, то есть:

Foo.createFromList(params)   // hypothetical

вместо записи:

Foo(params(0).asInstanceOf[Int], params(1).asInstanceOf[String], params(2).asInstanceOf[Double])

РЕДАКТИРОВАТЬ: кажется, что он сводится к возможности отправлять элементы спискав качестве параметров функции без явной записи их, например:

def bar(a: Int, b: Int, c: Int) = //...
val list = List(1, 2, 3, 4, 5)
bar(list.take(3)) // hypothetical, instead of:
bar(list(0), list(1), list(2))

Я бы ожидал, что смогу сделать:

bar(list.take(3): _*)

, но, похоже, это не работает.

РЕДАКТИРОВАТЬ: Решение, основанное на ответе extempore, но вызывающий конструктор напрямую вместо использования метода apply:

case class Foo(a: Int = 0, b: String = "bar", c: Double = 3.14) {
    val cs = this.getClass.getConstructors
    def createFromList(params: List[Any]) =
    cs(0).newInstance(params map { _.asInstanceOf[AnyRef] } : _*).asInstanceOf[Foo]
}

Теперь вы можете сделать:

scala> Foo().createFromList(List(4, "foo", 9.81))
res13: Foo = Foo(4,foo,9.81)

Вы также можете изменить метод создания в черту:

trait Creatable[T <: Creatable[T]] {
    val cs = this.getClass.getConstructors
    def createFromList(params: List[Any]) =
        cs(0).newInstance(params map { _.asInstanceOf[AnyRef] } : _*).asInstanceOf[T]   
}

case class Bar(a: Int = 0, b: String = "bar", c: Double = 3.14) extends Creatable[Bar]

И сделать, например:

scala> val bar = Bar()
bar: Bar = Bar(0,bar,3.14)

scala> bar == bar.createFromList(bar.productIterator.toList)
res11: Boolean = true

Ответы [ 3 ]

54 голосов
/ 28 ноября 2010
scala> case class Foo(a: Int, b: String, c: Double)
defined class Foo

scala> val params = Foo(1, "bar", 3.14).productIterator.toList
params: List[Any] = List(1, bar, 3.14)

scala> Foo.getClass.getMethods.find(x => x.getName == "apply" && x.isBridge).get.invoke(Foo, params map (_.asInstanceOf[AnyRef]): _*).asInstanceOf[Foo]
res0: Foo = Foo(1,bar,3.14)

scala> Foo(1, "bar", 3.14) == res0
res1: Boolean = true

Редактировать: кстати, синтаксис, который пока используется только для представления кортежа в качестве аргумента:

scala> case class Foo(a: Int, b: String, c: Double)
defined class Foo

scala> Foo.tupled((1, "bar", 3.14))                
res0: Foo = Foo(1,bar,3.14)
14 голосов
/ 27 ноября 2010

Ну, вы, безусловно, можете сделать это с помощью кортежа:

(Foo _).tupled apply (1, bar, 3.14)

Но нет реального способа получить от List[S] до (A, B, C) для A, B, C <: S. Может быть способ сделать это с HList с конечно

11 голосов
/ 27 ноября 2010

Вы можете использовать сопоставление с шаблоном как:

params match {                                   
 case List(x:Int, y:String, d:Double) => Foo(x,y,d)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...