从参数列表实例化案例类
鉴于:
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): _*)
但这似乎不起作用。
编辑:基于临时答案的解决方案,但直接调用构造函数而不是使用 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
Given:
case class Foo(a: Int, b: String, c: Double)
you can say:
val params = Foo(1, "bar", 3.14).productIterator.toList
and get:
params: List[Any] = List(1, bar, 3.14)
Is there a way to "go backwards" and recreate a Foo object directly from this list, i.e.:
Foo.createFromList(params) // hypothetical
instead of writing:
Foo(params(0).asInstanceOf[Int], params(1).asInstanceOf[String], params(2).asInstanceOf[Double])
EDIT: it seems that it boils down to being able to send the elements of a list as parameters to a function without writing them out explicitly, e.g.:
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))
I would sort of expect to be able to do:
bar(list.take(3): _*)
but that doesn't seem to work.
EDIT: Solution based on extempore's answer, but invoking the constructor directly instead of using the apply method:
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]
}
Now you can do:
scala> Foo().createFromList(List(4, "foo", 9.81))
res13: Foo = Foo(4,foo,9.81)
You can also refactor the creation method into a trait:
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]
And do e.g.:
scala> val bar = Bar()
bar: Bar = Bar(0,bar,3.14)
scala> bar == bar.createFromList(bar.productIterator.toList)
res11: Boolean = true
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
编辑:顺便说一句,到目前为止仅用于提供元组作为参数的语法是:
Edit: by the way, the syntax so far only being danced around for supplying the tuple as an argument is:
您可以使用模式匹配,例如:
You could use pattern matching like:
好吧,您当然可以使用元组来做到这一点:
但是没有真正的方法可以从
List[S]
到(A, B, C)
forA、B、C <:S
。可能有一种方法可以使用HList
s 当然Well, you can certainly do this with a tuple:
But there is no real way to get from a
List[S]
to(A, B, C)
forA, B, C <: S
. There may be a way of doing this withHList
s of course另一种衬垫使用案例类伴生对象柯里化方法并完全忽略类型安全:)
Another one liner using case class companion object curried method and completely ignoring type safety :)