我不知道在不可变对象上叫什么叫“setter”?
对于可变对象Person,setter的工作方式如下:
class Person(private var _name: String) {
def name = "Mr " + _name
def name_=(newName: String) {
_name = newName
}
}
val p = new Person("Olle")
println("Hi "+ p.name)
p.name = "Pelle"
println("Hi "+ p.name)
这一切都很好,但如果Person是不可变的呢?
class Person(private val _name: String) {
def name = "Mr " + _name
def whatHereName(newName: String): Person = new Person(newName)
}
val p = new Person("Olle")
println("Hi "+ p.name)
val p2 = p.whatHereName("Pelle")
println("Hi "+ p2.name)
whatHereName
应该被叫什么?
修改 我需要把东西放在“setter”方法中,如下所示:
class Person(private val _name: String) {
def name = "Mr " + _name
def whatHereName(newName: String): Person = {
if(name.length > 3)
new Person(newName.capitalize)
else
throw new Exception("Invalid new name")
}
}
真正的代码比这大得多,所以对copy
方法的简单调用是行不通的。
编辑2:
由于我的伪造示例有很多评论(这是不正确的)我最好给你link到真正的班级(Avatar
)。
我不知道该调用的“setter”方法是updateStrength
,updateWisdom
...但我很快就会将其更改为withStrength
..
答案 0 :(得分:13)
我喜欢jodatime的方式。这将是withName。
val p = new Person("Olle")
val p2 = p.withName("kalle");
更多jodatime示例:http://joda-time.sourceforge.net/
答案 1 :(得分:10)
为此,Scala案例类具有自动生成的方法 copy 。它的使用方式如下:
val p2 = p.copy(name = "Pelle")
答案 2 :(得分:4)
如果您在“修改”某个字段时需要执行验证等,那么为什么这与首次创建对象时的验证有何不同?
在这种情况下,您可以将必要的验证/错误抛出逻辑放在案例类的构造函数中,只要通过copy
方法创建新实例,就会使用此逻辑。
答案 3 :(得分:3)
您可以为此定义一种方法。 copy
,或者,如果已经是案例类,with
:
class Person(private val _name: String) {
def name = "Mr " + _name
def copy(name: String = _name): Person = new Person(name)
}
修改强>
链接示例上的copy
方法应如下所示:
// Setters
def copy(strength: Int = features.strength,
wisdom: Int = features.wisdom,
charisma: Int = features.charisma,
hitpoints: Int = features.hitpoints): Avatar = {
if (hitpoints != features.hitpoints)
println("setHitpoints() old value: " + features.hitpoints + ", new value: " + hitpoints)
if (hitpoints > 0)
updateCreatureFeature(
features.copy(strength = strength,
wisdom = wisdom,
charisma = charisma,
hitpoints = hitpoints))
else
throw new DeathException(name + " died!")
// Alternate coding (depend on thrown exception on "check"):
// check(strength, wisdom, charisma, hitpoints)
// updateCreateFeature(...)
}
答案 4 :(得分:2)
添加到Oleg的答案,你会写这样的类:
case class Person(name: String) //That's all!
您可以这样使用它:
val p = Person("Olle") // No "new" necessary
println("Hi" + p.name)
val p2 = p.copy(name="Pelle")
println("Hi" + p2.name)
使用上面的复制方法是可能的,但在你的简单情况下,我只会使用:
val p2 = Person("Pelle")
如果你有类似的课程,复制方法会显示出它们的优势:
case class Person(name: String, age: Int, email: EMail, pets: List[Pet] = List())
val joe = Person("Joe", 41, EMail("joe@example.com"))
val joeAfterHisNextBirthday = joe.copy(age=42)
答案 5 :(得分:1)
至于现在,我对不可变对象的所有“setter”类方法使用update<Field>
名称约定。
我不能使用set<Field>
,因为它提醒了Java中可变的setter。
对于返回与当前实例具有相同标识的新实例的所有方法,您如何使用update<Field>
?
答案 6 :(得分:0)
虽然以前的答案解决了这个问题,但我想分享一下我如何处理不可变对象(这只是语法糖)。
要有更清晰的语法(恕我直言),我在不可变类中实现apply
方法,在case类中返回copy
方法的结果,在常规类时返回新实例。即:
import java.util.Date
class Tournament (val name: String, val start: Date) {
/* With case class
def apply (name: String = this.name, start: Date = this.start) =
copy (name, start)
*/
def apply (name: String = this.name, start: Date = this.start) =
new Tournament (name, start)
override def toString () = s"${name} at ${start}"
}
object Main extends App {
val tour = new Tournament ("Euroleague", new Date)
val tour2 = tour (name = tour.name + " 2014")
println (tour)
println (tour2)
}
这使得“mutator”方法成为该类的任何实例的默认方法。