3

序列化以下案例类时,不包括 val 元素。为什么会这样,我可以把它包括在内吗?

case class Asset(id: Option[Int], description: Option[String]= None) {
  val url = "images/" + id.toString+".png"
}

更新:添加了 Json 库,以及 url“属性”的规范/预期用途。

我正在使用 Play 2.1/Scala 2.10 附带的 Json 库。

实际上 url 属性是一个函数,它将根据配置查找转换算法,例如图像可以在本地可用,也可以从外部主机可用。

4

1 回答 1

2

尽管您确实指定了您正在使用的 json 序列化库,但几乎可以保证只需执行以下操作即可:

case class Asset(id: Option[Int], description: Option[String]= None, url = "images/" + id.toString+".png")

鉴于它url无论如何都有一个默认值,将其转换为参数不会对您的代码产生负面影响(您仍然可以Asset(None)像以前一样通过示例进行操作)。唯一的缺点是现在客户端代码可能会创建一个Asset具有不同值的实例url,这可能不是您想要的。

如果是这种情况,您可能需要为您的Asset类创建自定义 json 格式,但在不知道您使用哪个序列化库的情况下,我在这方面无能为力。


更新

糟糕,我完全错过了默认值url取决于另一个参数 ( id) 的事实(感谢@Kristian Domagala 的注意)。因此,我上面的代码段无法编译。一个简单的解决方案是url按照@Kristian Domagala 的建议放入第二个参数列表:

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") ) )
  }
}

正如你所看到的,我已经变成urlOption一个默认值None(避免以前的编译错误,因为它不再依赖id),因为,并且我用默认值def apply...实例化了(这是我实际获得值的地方的) 的。Asseturlidid.map( "images/" + _ + ".png")

其余的基本上只是能够重新定义的噪音Asset.apply:事实证明,实际上您无法重新定义案例类的工厂(您只能添加单独的重载)。所以我将类重命名为AssetImpl,添加了一个类型别名以便没有人注意到 ( ;-) ),并创建了我自己的对象Asset,我在其中定义了apply方法(它不再与自动生成的apply方法冲突,因为这个在不同的AssetImpl对象。我也可以简单地变成Asset一个标准类(非案例类),但随后我将不得不重新定义equals并且hashCode我觉得更烦人,因为在向类添加/删除字段时必须维护它。

于 2013-02-13T15:47:25.937 回答