要在 Scala 中映射的案例类
有没有一种好的方法可以将 Scala case class
实例转换
case class MyClass(param1: String, param2: String)
val x = MyClass("hello", "world")
为某种映射,例如
getCCParams(x) returns "param1" -> "hello", "param2" -> "world"
适用于任何 case 类,而不仅仅是预定义的。 我发现您可以通过编写询问底层 Product 类的方法来提取案例类名称,例如,
def getCCName(caseobj: Product) = caseobj.productPrefix
getCCName(x) returns "MyClass"
所以我正在寻找类似的解决方案,但针对案例类字段。 我想象一个解决方案可能必须使用 Java 反射,但我不想编写一些如果案例类的底层实现发生变化的话可能会在 Scala 的未来版本中中断的东西。
目前,我正在开发 Scala 服务器,并使用案例类定义协议及其所有消息和异常,因为它们是一个如此美丽、简洁的构造。 但随后我需要将它们转换为 Java 映射,以便通过消息传递层发送以供任何客户端实现使用。 我当前的实现只是分别为每个案例类定义一个翻译,但最好找到一个通用的解决方案。
Is there a nice way I can convert a Scala case class
instance, e.g.
case class MyClass(param1: String, param2: String)
val x = MyClass("hello", "world")
into a mapping of some kind, e.g.
getCCParams(x) returns "param1" -> "hello", "param2" -> "world"
Which works for any case class, not just predefined ones. I've found you can pull the case class name out by writing a method that interrogates the underlying Product class, e.g.
def getCCName(caseobj: Product) = caseobj.productPrefix
getCCName(x) returns "MyClass"
So I'm looking for a similar solution but for the case class fields. I'd imagine a solution might have to use Java reflection, but I'd hate to write something that might break in a future release of Scala if the underlying implementation of case classes changes.
Currently I'm working on a Scala server and defining the protocol and all its messages and exceptions using case classes, as they are such a beautiful, concise construct for this. But I then need to translate them into a Java map to send over the messaging layer for any client implementation to use. My current implementation just defines a translation for each case class separately, but it would be nice to find a generalised solution.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
Scala 3 的现代变体也可能会稍微简化,如以下示例所示,该示例类似于 Walter Chang 如上所述。
Modern variation with Scala 3 might also be a bit simplified as with the following example that is similar to the answer posted by Walter Chang above.
使用Java反射,但访问级别没有改变。 将
Product
和 case 类转换为Map[String, String]
:With the use of Java reflection, but no change of access level. Converts
Product
and case class toMap[String, String]
:因为案例类扩展了 Product,所以可以简单地使用
.productIterator 来获取字段值:
或者:
Product 的一个优点是您无需在字段上调用
setAccessible
来读取其值。 另一个是productIterator不使用反射。请注意,此示例适用于简单的案例类,这些类不会扩展其他类,也不会在构造函数之外声明字段。
Because case classes extend Product one can simply use
.productIterator
to get field values:Or alternatively:
One advantage of Product is that you don't need to call
setAccessible
on the field to read its value. Another is that productIterator doesn't use reflection.Note that this example works with simple case classes that don't extend other classes and don't declare fields outside the constructor.
这应该有效:
This should work:
从 Scala 2.13 开始,
case 类
(作为Product
)随 productElementNames 方法,返回字段名称的迭代器。通过压缩字段名称和通过 productIterator 我们一般可以获取关联的
Map
:Starting
Scala 2.13
,case class
es (as implementations ofProduct
) are provided with a productElementNames method which returns an iterator over their field's names.By zipping field names with field values obtained with productIterator we can generically obtain the associated
Map
:如果有人寻找递归版本,这里是 @Andrejs 解决方案的修改:
它还将嵌套的案例类扩展为任何嵌套级别的映射。
If anybody looks for a recursive version, here is the modification of @Andrejs's solution:
It also expands the nested case-classes into maps at any level of nesting.
如果您不关心将其设为通用函数,那么这是一个简单的变体:
Here's a simple variation if you don't care about making it a generic function:
如果您碰巧使用 Json4s,您可以执行以下操作:
If you happen to be using Json4s, you could do the following:
使用解释器包中的
ProductCompletion
解决方案:Solution with
ProductCompletion
from interpreter package:我不知道nice...但这似乎有效,至少对于这个非常非常基本的例子来说。 它可能需要一些工作,但可能足以让您开始? 基本上它会过滤掉案例类(或任何其他类:/)中的所有“已知”方法
I don't know about nice... but this seems to work, at least for this very very basic example. It probably needs some work but might be enough to get you started? Basically it filters out all "known" methods from a case class (or any other class :/ )
你可以使用无形的。
让
定义一个LabelledGeneric表示
定义两个类型类来提供toMap方法
然后你可以像这样使用它。
打印
对于嵌套案例类,(因此嵌套映射)
检查另一个答案
You could use shapeless.
Let
Define a LabelledGeneric representation
Define two typeclasses to provide the toMap methods
Then you can use it like this.
which prints
For nested case classes, (thus nested maps)
check another answer
详细信息:https://github.com/hank-whu/common4s
Details: https://github.com/hank-whu/common4s