Scala var best practice - Encapsulation



例如,我试图了解在scala中使用vars的最佳实践是什么

class Rectangle() {
var x:Int = 0
}

或类似的东西:

class Rectangle() {
private var _x:Int = 0
def x:Int = _x
def x_(newX:Int):Unit = _x=newX
}

哪一个可以被认为是更好的?为什么? 谢谢!

正如 Luis 在评论中已经解释的那样,只要您能够避免它,vars 就应该避免,而像您给出的这样一个简单的案例是可以使用这样的东西更好地设计的情况之一:

// Companion object is not necessary in your case
object Rectangle {
def fromInt(x: Int): Option[Rectangle] = {
if(x > 0) {
Some(Rectangle(x))
} else None
}
final case class Rectangle(x: Int)

当你无法避免在scala中使用vars时,这将是非常罕见的情况。Scala的一般习语是:"让你的变量不可变,除非有充分的理由不这样做">

我试图了解在 scala 中使用变量的最佳实践是什么,[...]

最佳做法是根本不使用var

哪一个可以被认为是更好的?为什么?

第二个基本上等同于编译器为第一个生成的内容,因此使用第二个并没有真正的意义。

如果你想为二传手和吸气手提供不同的可访问性,这是有意义的,就像这样:

class Rectangle {
private[this] var _x = 0
def x = _x
private def x_=(x: Int) = _x = x
}

如您所见,我为setter和getter使用了不同的可访问性,因此明确地将它们写出来是有意义的。否则,只需让编译器生成它们。

注意:我对代码进行了一些其他更改:

  • 我将_x支持字段的可见性更改为private[this]
  • 我将二传手的名字改为x_=.这是 setter 的标准命名,它还有一个额外的优势,它允许您使用someRectangle.x = 42语法糖来调用它,使其与字段无法区分。
  • 我添加了一些空格,为代码提供了呼吸的空间。
  • 我删除了一些返回类型注释。(这个是有争议的。社区标准是始终在公共接口中注释您的返回类型,但在我看来,如果它们微不足道,您可以省略它们。弄清楚0Int型并不需要太多的精力。

请注意,您的第一个版本也可以简化:

class Rectangle(var x: Int = 0)

但是,正如其他答案中提到的,您确实应该使您的对象不可变。通过使用 case 类,可以轻松创建一个简单的不可变数据对象,其中包含自动生成的所有便利函数:

final case class Rectangle(x: Int = 0)

如果您现在想要"更改"矩形,请创建一个新矩形,该矩形具有除x之外的所有属性相同(在这种情况下,x是唯一的属性,但可能还有更多(。为此,Scala 为你生成了一个漂亮的copy方法:

val smallRectangle = Rectangle(3)
val enlargedRectangle = smallRectangle.copy(x = 10)

最新更新