鉴于:
case class Foo(a: Int, b: String, c: Double)
Run Code Online (Sandbox Code Playgroud)
你可以说:
val params = Foo(1, "bar", 3.14).productIterator.toList
Run Code Online (Sandbox Code Playgroud)
得到:
params: List[Any] = List(1, bar, 3.14)
Run Code Online (Sandbox Code Playgroud)
有没有办法"向后"并直接从此列表重新创建Foo对象,即:
Foo.createFromList(params) // hypothetical
Run Code Online (Sandbox Code Playgroud)
而不是写:
Foo(params(0).asInstanceOf[Int], params(1).asInstanceOf[String], params(2).asInstanceOf[Double])
Run Code Online (Sandbox Code Playgroud)
编辑:似乎它归结为能够将列表的元素作为参数发送到函数而不显式写出来,例如:
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))
Run Code Online (Sandbox Code Playgroud)
我希望能做到:
bar(list.take(3): _*)
Run Code Online (Sandbox Code Playgroud)
但这似乎不起作用.
编辑:解决方案基于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]
}
Run Code Online (Sandbox Code Playgroud)
现在你可以这样做:
scala> Foo().createFromList(List(4, "foo", 9.81))
res13: Foo = Foo(4,foo,9.81)
Run Code Online (Sandbox Code Playgroud)
您还可以将创建方法重构为特征:
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]
Run Code Online (Sandbox Code Playgroud)
并做例如:
scala> val bar = Bar()
bar: Bar = Bar(0,bar,3.14)
scala> bar == bar.createFromList(bar.productIterator.toList)
res11: Boolean = true
Run Code Online (Sandbox Code Playgroud)
psp*_*psp 55
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
Run Code Online (Sandbox Code Playgroud)
编辑:顺便说一句,到目前为止,语法只是为了提供元组作为参数而跳舞:
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)
Run Code Online (Sandbox Code Playgroud)
oxb*_*kes 14
好吧,你当然可以用元组做到这一点:
(Foo _).tupled apply (1, bar, 3.14)
Run Code Online (Sandbox Code Playgroud)
但有从得到没有真正的方法List[S]来(A, B, C)进行A, B, C <: S.可能有这样的一种方式HList小号,当然
bja*_*tek 11
您可以使用模式匹配,如:
params match {
case List(x:Int, y:String, d:Double) => Foo(x,y,d)
}
Run Code Online (Sandbox Code Playgroud)