+ = for immutable Set的语法

时间:2016-06-30 21:12:20

标签: scala

对于可变的Set + =方法(运算符)将产生副作用并更改集合本身。举个例子:

class Button: Sprite, Wable {
    // needs s(); inherited from Sprite
    // needs w(); inherited from Wable
}

class Cursor: Element, Wable {
    // needs s(); inherited from Sprite
    // needs w(); inherited from Wable
    // needs e(); inherited from Element
}

class Pointer: Element, Wable  {
    // needs w(); inherited from Wable
    // needs e(); inherited from Element
}

protocol Wable {
    func W()
}

extension Wable where Self : Sprite {
    func W() {
        print("foo")
    }
}

在上面的示例中,未创建Set的新实例,但现有的实例已发生变异。 + =是可变Set的实际方法,因此我们可以将最后一行写为:

val mySet = scala.collection.mutable.Set(1, 2, 3)
mySet += 4

但是对于不可变Set,当我们使用+ =时,会创建一个新的Set实例:

mySet.+=(4)

为什么+ =不是不可变集合的实际方法,即使我们使用它就像应用于Set的方法一样?

3 个答案:

答案 0 :(得分:4)

  

我的问题是基于这本书我正在阅读为什么+=不是一个不可变的Set的实际方法,即使我们将它用作应用于Set的方法?

不可变+=(或任何其他不可变集合)没有Set方法。

规则是,如果类型检查,则a ω= b形式的运算符赋值表达式首先被解释为a.ω=(b),但如果它不进行类型检查,则它会被解释为a = a ω b(提供 类型检查)。

因此,myOtherSet += 4的作用原因是定义了+方法,myOtherSetvar,表达式被解释为myOtherSet = myOtherSet + 4 }。

答案 1 :(得分:2)

如果你有一个 var ,那么+ =代表一个赋值和+,即x + = y被转换为x = x + y。在这种情况下,+ =不是方法,而是语法糖。除非,如果定义了明确的+ =方法。

这不仅适用于Set,也适用于所有类型。请考虑以下示例:

case class NewInt(var x : Int) {  
  def +(y: Int) = { println("+"); NewInt(x + y) }
}

var n = NewInt(3)
n += 3 // outputs +, n == NewInt(6) now
val n2 = NewInt(3)
n2 += 3 // error

case class SuperInt(var x : Int) {
  def +=(y: Int) = { println("+="); x = x + y }
  def +(y: Int) = { println("+"); SuperInt(x + y) }
}

var n3 = SuperInt(3)
n3 += 3 // outputs +=, n3 == SuperInt(6)
val n4 = SuperInt(3)
n4 += 3 // outputs +=, n4 == SuperInt(6)

答案 2 :(得分:1)

  

为什么我们不能称它为不可变Set的实际方法?

最明显的是因为在不可变的+=类或其任何超类中没有定义方法Set(也没有任何隐式转换存在的类)。

它在某些方面的作用与方法不同:

  • 如果+=myOtherSet而不是var,则您只能使用val。你也不能在变量以外的任何东西上使用它。方法可用于对方法类进行求值的任何类型的表达式,无论它是valvar还是某种其他类型的表达式。
  • 包含不可变对象的+=上的
  • var将使变量指向不同的对象(因为显然您无法更改对象本身)。因此,在您执行myOtherSet += 4后,myOtherSet的身份会发生变化。方法永远不会那样做。