具有val字段的Scala不可变对象和特征 [英] Scala immutable objects and traits with val fields

查看:71
本文介绍了具有val字段的Scala不可变对象和特征的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只想使用不可变对象来构建域模型.但我也想将特征与val字段一起使用,并将某些功能移至特征.请看下面的例子:

I would like to construct my domain model using immutable objects only. But I also want to use traits with val fields and move some functionality to traits. Please look at the following example:

trait Versionable {
 val version = 0
 def incrementVersion = copy(version=version+1)
}

不幸的是,这样的代码不起作用-特征可版本控制的复制方法未知.

Unfortunatelly such code doesn't work - copy method is unknown for trait Versionable.

我认为最好为每个特征和类生成复制方法.这种方法应创建对象的浅表副本,并使用与原始对象相同的类型返回它,并根据传递给方法的参数修改给定字段.

I think that it would be nice to have copy method generated for every trait and class. Such method should create shallow copy of object and return it using the same type as for original object with given field modified accoring to arguments passed to method.

因此在以下示例中:

class Customer(val name: String) extends Versionable {
 def changeName(newName: String) = copy(name = newName)
}

val customer = new Customer("Scot")

customer.changeName("McDonnald")应该返回一个对象实例Customer(version = 0, name = "McDonnald")

customer.changeName("McDonnald") should return an object instance Customer(version = 0, name = "McDonnald")

customer.incrementVersion还应该返回一个对象实例Customer(version = 1, name = "Scot")

customer.incrementVersion should also return an object instance Customer(version = 1, name = "Scot")

据我所知,Scala当前缺乏这种功能不允许使用不可变的类和特征,而不会用特征字段污染类构造函数.在我的示例中,我不想将名为version的参数引入Customer类,因为我希望将版本处理的功能封装在Versionable特性中.

As far as I know current lack of such functionality in Scala doesn't allow to use immutable classes and traits without polluting class constructor with trait fields. In my example I don't want to introduce parameter named version to Customer class because functionality of version handling I want to have encapsulated in Versionable trait.

我知道案例类中复制方法的功能以及使用默认参数在类中编写自己的复制方法的能力-但我认为此功能无法解决我的问题,因为无法使用此类复制方法特质.现有功能的另一个缺点是使用复制方法的父类将返回父类,而不是实际复制的对象类.

我的问题:

1)您是否知道如何以优雅的方式处理上述示例.我对Scala还是很陌生,所以也许已经有了不错的解决方案.我认为优雅的解决方案应具有以下功能:

1) do you have idea how to handle above example in elegant way. I'm quite new to Scala so maybe there is good solution already. In my opinion elegant solutions should have following features:

  • 不应使用反射

  • should not use reflection

不应使用序列化

应该很快

应在编译时进行验证

2)对于上面的示例,您如何看待编写编译器插件以生成用于复制方法的代码?是否可以使用编译器插件来做到这一点?您有任何示例或提示如何实现吗?

2) what do you think about writing compiler plugin to generate code for copy method for my above example? Is it possible to do that using compiler plugin? Do you have any examples or tips how to do that?

推荐答案

最干净的解决方案可能是从Versionable删除一些实现逻辑,并将其推入类型堆栈到case类(其中copy方法将可供您使用).为version属性提供默认值以完成设计.

You cleanest solution is probably to drop some implementation logic from Versionable, and push it down the type stack to a case class (where the copy method will be available to you). Give the version property a default value to complete the design.

trait Versioned {
  def version : Int
  def nextVersion = version + 1 
}

case class Customer(name: String, version : Int = 0) extends Versioned {
  def withName(newName: String) = copy(name = newName, version = nextVersion)
}

如果需要,还可以在版本编号的某处定义类型别名:

If you want, you can also define a type alias somewhere for the version numbering:

type Version = Int
val initialVersion = 0

trait Versioned {
  def version : Version
  def nextVersion = version + 1 
}

case class Customer(name: String, version : Version = initialVersion)
extends Versioned {
  def withName(newName: String) = copy(name = newName, version = nextVersion)
}

这篇关于具有val字段的Scala不可变对象和特征的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆