“setter”的 Scala 命名约定在不可变对象上

发布于 2024-09-28 10:08:17 字数 1411 浏览 7 评论 0原文

我不知道如何称呼不可变对象上的“设置器”?

对于可变对象 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:

由于我的伪造示例有很多评论(这是不正确的),我最好给您链接到真实的类(Avatar)。

我不知道该调用什么的“setter”方法是 updateStrengthupdateWisdom ...但我可能很快就会将其更改为 withStrength ..

I do not know what to call my "setters" on immutable objects?

For a mutable object Person, setters work like this:

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)

This is all well and good, but what if Person is immutable?

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)

What should whatHereName be called?

EDIT:
I need to put stuff in the "setter" method, like this:

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

The real code is much bigger than this, so a simple call to the copy method will not do.

EDIT 2:

Since there are so many comments on my faked example (that it is incorrect) I better give you the link to the real class (Avatar).

The "setter" methods I don't know what to call are updateStrength, updateWisdom ... but I will probably change that to withStrength soon..

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

老子叫无熙 2024-10-05 10:08:17

我喜欢乔达时间的方式。那就是withName。

val p = new Person("Olle")
val p2 = p.withName("kalle");

更多jodatime示例:http://joda-time.sourceforge.net/

I like the jodatime way. that would be withName.

val p = new Person("Olle")
val p2 = p.withName("kalle");

more jodatime examples: http://joda-time.sourceforge.net/

愿得七秒忆 2024-10-05 10:08:17

为此,Scala 案例类具有自动生成的方法 copy。它的使用方式如下:
<代码>

val p2 = p.copy(name = "Pelle")

Scala case classes have autogenerated method copy for this purpose. It's used like this:

val p2 = p.copy(name = "Pelle")

沙沙粒小 2024-10-05 10:08:17

如果您在“修改”字段时需要执行验证等,那么为什么这与首次创建对象时的验证有任何不同

在这种情况下,您可以将必要的验证/错误抛出逻辑放入案例类的构造函数中,每当通过 copy 方法创建新实例时都会使用该逻辑。

If you need to perform validation, etc. when 'modifying' a field, then why should this be any different from validation when you first create the object?

In this case, you can then put the necessary validation/error-throwing logic in the constructor of a case class, and this will be used whenever a new instance is created via the copy method.

嗫嚅 2024-10-05 10:08:17

您可以为此定义一个方法。 copy,或者,如果它已经是一个案例类,with

class Person(private val _name: String) {
  def name = "Mr " + _name
  def copy(name: String = _name): Person = new Person(name)
}

EDIT

上的 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(...)
}

You could define a single method for that. Either copy, or, in case it is already a case class, with:

class Person(private val _name: String) {
  def name = "Mr " + _name
  def copy(name: String = _name): Person = new Person(name)
}

EDIT

The copy method on the linked example should look like this:

// 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(...)
}
枉心 2024-10-05 10:08:17

添加到奥列格答案中,您将这样编写该类:

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("[email protected]"))
val joeAfterHisNextBirthday = joe.copy(age=42)

Adding to Oleg answer, you would write the class like this:

case class Person(name: String) //That's all!

You would use it like this:

val p = Person("Olle") // No "new" necessary
println("Hi" + p.name)
val p2 = p.copy(name="Pelle")
println("Hi" + p2.name)    

Using the copy method like above is possible, but in your simple case I would just use:

val p2 = Person("Pelle")

The copy methods show their strengths if you have classes like:

case class Person(name: String, age: Int, email: EMail, pets: List[Pet] = List())
val joe = Person("Joe", 41, EMail("[email protected]"))
val joeAfterHisNextBirthday = joe.copy(age=42)
久光 2024-10-05 10:08:17

目前,我对不可变对象上的所有类似“setter”的方法使用 update 名称约定。

我无法使用 set 因为它过多地提醒了 Java 中的可变设置器。

对于返回与当前实例具有相同标识的新实例的所有方法,您感觉如何?

As for now I am using update<Field> name convention for all "setter"-like methods on immutable objects.

I can not use set<Field> since it reminds too much about the mutable setters in Java.

How do you feel about using update<Field> for all methods that returns a new instance of the same identity as the current instance?

¢好甜 2024-10-05 10:08:17

尽管之前的答案解决了问题,但我想分享一下我如何处理不可变对象(这只是语法糖)。

为了有更清晰的语法(恕我直言),我在不可变类中实现了apply方法,在案例类中返回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”方法成为该类的任何实例的默认方法。

Though previous answers resolve the problem, I would like to share how I deal with immutable objects (which is only syntactic sugar).

To have a clearer syntax (IMHO) I implement the apply method in immutable classes, returning the result of the copy method in case classes and a new instance when it is a regular class. ie:

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

This makes the "mutator" method the default method for any instance of that class.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文