Scala +;=关于不可变集

Scala +;=关于不可变集,scala,Scala,对于可变集合+=方法(运算符)将产生副作用并更改集合本身。例如: val mySet = scala.collection.mutable.Set(1, 2, 3) mySet += 4 在上面的示例中,未创建Set的新实例,但对现有实例进行了修改是可变集的实际方法,因此我们可以将最后一行写成: mySet.+=(4) 但是,对于不可变集合,当我们使用+=时,将创建一个新集合实例: var myOtherSet = Set(1, 2, 3) myOtherSet += 4 为什么+=不是不

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

val mySet = scala.collection.mutable.Set(1, 2, 3)
mySet += 4
在上面的示例中,未创建Set的新实例,但对现有实例进行了修改是可变集的实际方法,因此我们可以将最后一行写成:

mySet.+=(4)
但是,对于不可变集合,当我们使用+=时,将创建一个新集合实例:

var myOtherSet = Set(1, 2, 3)
myOtherSet += 4
为什么+=不是不可变集合的实际方法,即使我们将其用作应用于集合的方法

为什么我们不能称之为不可变集合的实际方法

最明显的原因是在不可变的
集合
类或其任何超类(或存在隐式转换的任何类)中未定义任何方法

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

  • 如果
    myOtherSet
    var
    而不是
    val
    ,则只能使用
    +=
    。除变量外,您也不能在任何其他对象上使用它。方法可用于对方法类求值的任何类型的表达式,无论它是
    val
    var
    还是其他类型的表达式
  • 包含不可变对象的
    var
    上的
    +=
    将使变量指向不同的对象(因为显然您无法更改对象本身)。因此,在执行
    myOtherSet+=4
    之后,
    myOtherSet
    的标识会发生变化。一种方法永远不能做到这一点
为什么我们不能称之为不可变集合的实际方法

最明显的原因是在不可变的
集合
类或其任何超类(或存在隐式转换的任何类)中未定义任何方法

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

  • 如果
    myOtherSet
    var
    而不是
    val
    ,则只能使用
    +=
    。除变量外,您也不能在任何其他对象上使用它。方法可用于对方法类求值的任何类型的表达式,无论它是
    val
    var
    还是其他类型的表达式
  • 包含不可变对象的
    var
    上的
    +=
    将使变量指向不同的对象(因为显然您无法更改对象本身)。因此,在执行
    myOtherSet+=4
    之后,
    myOtherSet
    的标识会发生变化。一种方法永远不能做到这一点
如果您有一个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)
如果您有一个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)
我的问题是,根据我正在读的那本书,为什么
+=
不是不可变
Set
的实际方法,即使我们使用它作为应用于
Set
的方法

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

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

因此,
myOtherSet+=4
起作用的原因是定义了一个
+
方法,
myOtherSet
是一个
var
,表达式被解释为
myOtherSet=myOtherSet+4

我的问题是,根据我正在读的那本书,为什么
+=
不是不可变
Set
的实际方法,即使我们使用它作为应用于
Set
的方法

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

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


因此,
myOtherSet+=4
起作用的原因是定义了一个
+
方法,
myOtherSet
是一个
var
,表达式被解释为
myOtherSet=myOtherSet+4

谢谢您的回答,没有了解对象的类型检查意味着什么,我们如何知道对象类型检查与否?也许类型检查是指为对象定义了一个名为ω=的方法?谢谢你的回答,我不知道类型检查对对象意味着什么,我们如何知道对象类型检查与否?可能通过类型检查,您的意思是为对象定义了一个名为ω=的方法?MyOtherSet+=4被转换为MyOtherSet=MyOtherSet+4,可变集和不可变集的+运算符都返回一个新集。在这种情况下,不可变集合的+=a被转换为x=x+a,因此返回一个新集合,因此我们只能对其使用var。总之,解释+=的方式取决于对象本身(它是否有+=方法),而不是var或val,我认为。@iman“myOtherSet+=4”对于可变集不会转换为
myOtherSet=myOtherSet+4
。它只调用可变集合上的
+=
方法。“总之,解释+=的方式取决于对象本身(它是否有+=方法),而不是var或val。”是的,但如果
+=
被解释为赋值,我们就不能在
val
上使用它。这就是重新分配歌剧之间的一个区别