我正在阅读结构化JSON,使用Play Frameworks的JSON Reads来构建带有案例类的对象图 .
一个例子:
case class Foo (
id: Int,
bar_id: Int,
baz_id: Int,
x: Int,
y: String
)
{
var bar: Bar = null
var baz: Baz = null
}
在建造Foo之后,我必须稍后回来并通过设置bar和baz来装饰它 . 这些在其他JSON文件中定义,仅在所有解析完成时才知道 . 但这意味着Foo不可能是不可变的 .
Scala中制作不可变对象的“正确”方式是什么,然后是它的装饰版本,而不是一遍又一遍地重复Foo的每个字段?
我知道几种感觉错误的方法:
-
make "bar: Option[Bar]"和"baz: Option[Baz]" case类参数,然后我可以使用"copy"来创建Foo类的新版本,并将它们设置为某个东西;但是我必须每次访问它们都要检查它们 - 效率低,不安全,不能制作一个只保证具有正确结构的DecorativeFoo
-
制作第二个案例类,它是第一个案例中所有结构的复制粘贴,但添加了两个额外的修饰参数 - 但这意味着在定义中回显整个参数列表,并在创建它的实例时再次
-
案例类继承显然是有争议的,无论如何似乎也要求我在子类构造函数中重复每一个参数?
-
创建一个列出常见案例类参数的非案例超类 . 然后在case类中扩展它 . 但这似乎仍然需要重复子类构造函数中的每个单个参数 .
-
我看到人们谈论这个问题的博客,并在运行时使用反射来填充其装饰副本的基本属性 - 这避免了回声,但现在你没有类型安全,指定属性名称为字符串,开销等...
当然,Scala必须有办法让人们用更简单的对象组成更复杂的不可变对象,而不必手工复制它们的每一部分?
3 回答
结合
Option
和类型参数,您可以标记案例类,并静态地跟踪已处理的字段是否为空:用例示例:
我在目前的项目中使用过一次 . 我遇到的主要问题是当我希望
Foo
是协变的时候 .或者,如果您不关心
T
上的界限:然后你可以在需要
Foo[Option]
时使用Foo[Unprocessed]
或Foo[Processed]
.另一种策略可能是创建另一个案例类:
您可以为已处理的类型引入一个新特征,一个扩展该特征的类,以及一个隐式转换:
那么你可以这样做:
并且,尽管
withBaz
返回FooWithBaz
,但由于隐式转换,我们可以在必要时将返回值视为Foo
.