对于可变的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的方法一样?
答案 0 :(得分:4)
我的问题是基于这本书我正在阅读为什么
+=
不是一个不可变的Set
的实际方法,即使我们将它用作应用于Set
的方法?
不可变+=
(或任何其他不可变集合)没有Set
方法。
规则是,如果类型检查,则a ω= b
形式的运算符赋值表达式首先被解释为a.ω=(b)
,但如果它不进行类型检查,则它会被解释为a = a ω b
(提供 类型检查)。
因此,myOtherSet += 4
的作用原因是定义了+
方法,myOtherSet
是var
,表达式被解释为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
。你也不能在变量以外的任何东西上使用它。方法可用于对方法类进行求值的任何类型的表达式,无论它是val
,var
还是某种其他类型的表达式。+=
上的var
将使变量指向不同的对象(因为显然您无法更改对象本身)。因此,在您执行myOtherSet += 4
后,myOtherSet
的身份会发生变化。方法永远不会那样做。