从参数列表实例化案例类

发布于 2024-10-04 20:55:15 字数 1797 浏览 2 评论 0原文

鉴于:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

蹲在坟头点根烟 2024-10-11 20:55:15
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)
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

Edit: by the way, the syntax so far only being danced around for supplying the tuple as an argument is:

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)
傲世九天 2024-10-11 20:55:15

您可以使用模式匹配,例如:

params match {                                   
 case List(x:Int, y:String, d:Double) => Foo(x,y,d)
}

You could use pattern matching like:

params match {                                   
 case List(x:Int, y:String, d:Double) => Foo(x,y,d)
}
初懵 2024-10-11 20:55:15

好吧,您当然可以使用元组来做到这一点:

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

但是没有真正的方法可以从 List[S](A, B, C) for A、B、C <:S。可能有一种方法可以使用 HLists 当然

Well, you can certainly do this with a tuple:

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

But there is no real way to get from a List[S] to (A, B, C) for A, B, C <: S. There may be a way of doing this with HLists of course

ぃ双果 2024-10-11 20:55:15

另一种衬垫使用案例类伴生对象柯里化方法并完全忽略类型安全:)

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

scala> val lst = List(1, "bar", 3.14)
lst: List[Any] = List(1, bar, 3.14)

scala> val foo = lst.foldLeft(Foo.curried: Any){case (r, v) => r.asInstanceOf[Function[Any, _]](v) }.asInstanceOf[Foo]
foo: Foo = Foo(1,bar,3.14)

Another one liner using case class companion object curried method and completely ignoring type safety :)

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

scala> val lst = List(1, "bar", 3.14)
lst: List[Any] = List(1, bar, 3.14)

scala> val foo = lst.foldLeft(Foo.curried: Any){case (r, v) => r.asInstanceOf[Function[Any, _]](v) }.asInstanceOf[Foo]
foo: Foo = Foo(1,bar,3.14)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文