虽然你应该确切地指定你使用的json序列化库,但以下操作几乎可以保证可行:
case class Asset(id: Option[Int], description: Option[String]= None, url = "images/" + id.toString+".png")
鉴于
url
已经有了默认值,将其变成参数不会对您的代码产生负面影响(例如,您仍然可以像以前一样执行
Asset(None)
)。唯一的缺点是现在客户端代码可能会为
url
创建一个具有不同值的
Asset
实例,这可能不是您想要的。
如果是这种情况,您可能需要为
Asset
类创建自定义JSON格式,但是如果不知道您使用的序列化库,则在这方面我无法提供更多帮助。
更新:
糟糕,我完全忽略了
url
的默认值取决于另一个参数(
id
)(感谢@Kristian Domagala注意到这一点)。因此,我的上面的片段无法编译。一个简单的解决方案是按照@Kristian Domagala的建议将
url
放在第二个参数列表中:
case class Asset(id:Option[Int],description:Option[String]=None)(val url:String = "images/" + id.toString+".png")
但这可能不是理想的,因为它改变了Asset
的等同语义(在比较实例时不再考虑url
),并且也改变了构造语法:当明确指定url
值时,您需要执行类似于Asset(Some(123))("gfx/myImage.png")
而不是例如Asset(Some(123), url="gfx/myImage.png")
。
如果您可以容忍这些缺点,这肯定是最简单的解决方案。
否则,还有另一个解决方法:我们可以手动重新定义Asset.apply
:
case class AssetImpl( val id: Option[Int], val description: Option[String], val url: Option[String]) {
override def productPrefix = "Asset"
}
type Asset = AssetImpl
object Asset {
def apply( id: Option[Int], description: Option[String] = None, url: Option[String] = None ) = {
new Asset( id, description, url.orElse( id.map( "images/" + _ + ".png") ) )
}
}
如你所见,我已经将url
转换为一个带有默认值None
的Option
(避免了以前的编译错误,因为它不再依赖于id
),在def apply...
中,我使用id.map( "images/" + _ + ".png")
来实例化具有默认值的url
的Asset
(这里实际上获取了id
的值)。
其余部分基本上只是为了重新定义Asset.apply
:事实证明,您实际上不能重新定义案例类的工厂(您只能添加单独的重载)。因此,我将该类重命名为AssetImpl
,并添加了一个类型别名,以便没有人注意到(;-)),并创建了自己的对象Asset
,在其中定义了apply
方法(这不再与自动生成的apply
方法冲突,因为后者在不同的AssetImpl
对象中)。
我也可以简单地将Asset
转换为标准类(非案例类),但这样我就必须重新定义equals
和hashCode
,我发现这更令人烦恼,因为它必须在向类添加/删除字段时进行维护。
id
,需要在第二个参数组中声明url
。我最初对答案进行了负面评价,认为序列化库不会捕获第二个参数组,但事实证明Jerkson确实可以序列化它。完整的声明应该是case class Asset(id:Option[Int],description:Option[String]=None)(val url:String = "images/" + id.toString+".png")
。顺便说一句,考虑到Option.toString
的实现方式,我认为url
的值可能不是预期的。 - Kristian Domagalaurl
->id
的依赖关系。我已经更新了我的答案。 - Régis Jean-Gilles