我如何反思性地创建一个新的集合?

发布于 2024-10-05 12:18:35 字数 446 浏览 1 评论 0原文

我有一个集合实例,我想将其存储在外部,然后恢复到原始集合类型。例如,

class Foo {
  var x : List[Int]
}

val f = new Foo
f.x = List(1, 2, 3)

我“序列化”出 f,我想反射性地创建一个新的 Foo、f2,并使用正确的结果填充 f2.x。

我可以通过执行 classOf[Foo].newInstance 创建新的 Foo,但是如何创建正确的集合类型并填充它呢?

请注意,我在这里做了很多假设,值得注意的是: 1)我知道 fx 的类型,我什至可以序列化出它的类型 2)我将 x 的内容序列化为保留值的内容 3)我不想使用任何“标准”序列化

我尝试使用原始集合上可用的构建器,但我不太明白它是如何工作的足以实现它。

谢谢,

戴夫

I have an instance of a collection that I want to store externally and then restore back into the original collection type. For example

class Foo {
  var x : List[Int]
}

val f = new Foo
f.x = List(1, 2, 3)

I "serialize" out f, I want to reflectively create a new Foo, f2, and populate f2.x with the correct results.

I can create the new Foo by doing classOf[Foo].newInstance, but how do I then create the correct collection type and populate it?

Note, I'm making lots of assumptions here, notable:
1) I know the type of f.x, and I can even serialize out the type of that
2) I'm serializing out the contents of x into something that preserves the values
3) I don't want to use any "standard" serialization

I've tried to use the builders available on the original collection, but I don't quite understand how that works enough to pull it off.

Thanks,

Dave

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(1

独留℉清风醉 2024-10-12 12:18:36

如果我们对您要解决的问题有更好的了解,例如为什么您不想使用标准对象序列化,那么在这里提供帮助会更容易。

也就是说,如果您确实想要对 Scala 集合类进行反射,您可能需要了解一些有关 Scala 当前如何编译其类和对象的信息:

  • 如果您想要 List 对象的类(而不是对于 List 类),名称为 scala.collection.immutable.List$ - 请注意最后的美元符号。

  • 如果您想要单例 List 对象实例,则将其存储为字段 MODULE$

  • 大多数 scala 集合伴随对象提供一个 newBuilder 方法,该方法创建一个具有 += ($plus$eq) 方法的对象,并且允许您创建新集合的 result 方法。

所以你可以这样做:

scala> def buildByReflection[T](collectionClassName: String, items: Array[T]) = {
     |   val companionClass = Class.forName(collectionClassName + "$")
     |   val companion = companionClass.getField("MODULE$").get(null)
     |   val newBuilder = companionClass.getMethod("newBuilder")
     |   val builder = newBuilder.invoke(companion)
     |   val plusEq = builder.getClass.getMethod("$plus$eq", classOf[Object])
     |   for (item <- items) {
     |     plusEq.invoke(builder, item.asInstanceOf[AnyRef])
     |   }
     |   builder.getClass.getMethod("result").invoke(builder)
     | }
buildByReflection: [T](collectionClassName: String,items: Array[T])java.lang.Object

scala> buildByReflection("scala.collection.immutable.List", Array(1, 2, 3))
res0: java.lang.Object = List(1, 2, 3)

It would be easier to help here if we had a better idea of the problem you're trying to solve, e.g. why you don't want to use the standard object serialization.

That said, if you really do want to do reflection over Scala collection classes, you'll probably need to know a few things about how Scala currently compiles its classes and objects:

  • If you want the class for the List object (not for the List class), the name is scala.collection.immutable.List$ - note the final dollar sign.

  • If you want the singleton List object instance, that's stored as the field MODULE$.

  • Most scala collection companion objects provide a newBuilder method which creates an object that has a += ($plus$eq) method and a result method that allow you to create a new collection.

So you could do something like:

scala> def buildByReflection[T](collectionClassName: String, items: Array[T]) = {
     |   val companionClass = Class.forName(collectionClassName + "$")
     |   val companion = companionClass.getField("MODULE$").get(null)
     |   val newBuilder = companionClass.getMethod("newBuilder")
     |   val builder = newBuilder.invoke(companion)
     |   val plusEq = builder.getClass.getMethod("$plus$eq", classOf[Object])
     |   for (item <- items) {
     |     plusEq.invoke(builder, item.asInstanceOf[AnyRef])
     |   }
     |   builder.getClass.getMethod("result").invoke(builder)
     | }
buildByReflection: [T](collectionClassName: String,items: Array[T])java.lang.Object

scala> buildByReflection("scala.collection.immutable.List", Array(1, 2, 3))
res0: java.lang.Object = List(1, 2, 3)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文