Scala 设置不变性
Scala Sets Immutability
scala> var immSet = Set("A", "B")
immSet: scala.collection.immutable.Set[String] = Set(A, B)
scala> immSet += "C"
scala> println(immSet)
Set(A, B, C)
我想知道,允许 var
与不可变 Set 一起使用有什么好处?在这种情况下我不会失去不变性吗?
What is the advantage I am getting by allowing var
to be used with
with a Immutabable Set
s?
我想说这主要会引起混乱。您使用 var
的事实允许您 覆盖变量 ,但是 Set
本身 不会改变,它分配一个带有附加值"C"的新集合。但是由于您使用的是 var
,现在不再引用之前的 Set
,除非您引用的是堆栈中更高的其他地方:
scala> var firstSet = Set("A", "B")
firstSet: scala.collection.immutable.Set[String] = Set(A, B)
scala> var secondSet = firstSet
secondSet: scala.collection.immutable.Set[String] = Set(A, B)
scala> firstSet += "C"
scala> firstSet
res6: scala.collection.immutable.Set[String] = Set(A, B, C)
scala> secondSet
res7: scala.collection.immutable.Set[String] = Set(A, B)
因为 secondSet
仍然指向由 firstSet
创建的 Set
,我们没有看到反映的值更新。我认为使这个不可变增加了底层 Set
不可变以及指向它的变量的清晰度。当您使用 val
时,如果您尝试重新分配,编译器会大喊大叫,迫使您意识到已初始化一个新集合。
关于不变性,我们需要把它分成两部分。有 Set
的不变性,还有指向 Set
的变量的不变性,这是两个不同的东西。你用这种方法失去了后者。
如果您想了解定义为 var
的不可变集合和定义为 val
的可变集合之间的基本区别,请阅读@YuvalItzchakov 的回答。我将专注于这两种方法的实际方面。
首先,这两种方法都意味着可变性。如果你想留下来 "pure functional" 你应该避免其中任何一个。
现在,如果你想要可变集合,最好的方法是什么?简短的回答,这取决于。
性能。可变集合通常比不可变集合更快。这意味着,如果您的可变变量以某种方式包含(例如,不转义私有方法),则使用 val c = MutableCollection()
可能更好。 Collections API 中的大多数 Scala 方法在内部使用可变集合。
线程安全。不可变集合的值始终是线程安全的。您可以将它发送到另一个线程,而不考虑可见性和并发更改。
var a = ImmutableCol()
otherThreadProcessor.process(a)
a += 1 // otherThread will still have previous value
另一方面,如果你想从多线程修改集合,最好使用Java的并发集合API。
代码清晰。想象一下,您有一些函数将集合作为参数,然后以某种方式对其进行修改。如果集合是可变的,那么在函数 returns 之后,作为参数传递的集合将保持修改状态。
def recImmutable(a:Set[Int]): Unit = {
var b = a
b += 4
}
val a = Set(2,3)
recImmutable(a)
println(a)
// prints Set(2, 3)
def recMutable(a:mutable.Set[Int]): Unit = {
var b = a
b += 4
}
val b = mutable.Set(2,3)
recMutable(b)
println(b)
// prints Set(2, 3, 4)
scala> var immSet = Set("A", "B")
immSet: scala.collection.immutable.Set[String] = Set(A, B)
scala> immSet += "C"
scala> println(immSet)
Set(A, B, C)
我想知道,允许 var
与不可变 Set 一起使用有什么好处?在这种情况下我不会失去不变性吗?
What is the advantage I am getting by allowing
var
to be used with with a ImmutabableSet
s?
我想说这主要会引起混乱。您使用 var
的事实允许您 覆盖变量 ,但是 Set
本身 不会改变,它分配一个带有附加值"C"的新集合。但是由于您使用的是 var
,现在不再引用之前的 Set
,除非您引用的是堆栈中更高的其他地方:
scala> var firstSet = Set("A", "B")
firstSet: scala.collection.immutable.Set[String] = Set(A, B)
scala> var secondSet = firstSet
secondSet: scala.collection.immutable.Set[String] = Set(A, B)
scala> firstSet += "C"
scala> firstSet
res6: scala.collection.immutable.Set[String] = Set(A, B, C)
scala> secondSet
res7: scala.collection.immutable.Set[String] = Set(A, B)
因为 secondSet
仍然指向由 firstSet
创建的 Set
,我们没有看到反映的值更新。我认为使这个不可变增加了底层 Set
不可变以及指向它的变量的清晰度。当您使用 val
时,如果您尝试重新分配,编译器会大喊大叫,迫使您意识到已初始化一个新集合。
关于不变性,我们需要把它分成两部分。有 Set
的不变性,还有指向 Set
的变量的不变性,这是两个不同的东西。你用这种方法失去了后者。
如果您想了解定义为 var
的不可变集合和定义为 val
的可变集合之间的基本区别,请阅读@YuvalItzchakov 的回答。我将专注于这两种方法的实际方面。
首先,这两种方法都意味着可变性。如果你想留下来 "pure functional" 你应该避免其中任何一个。
现在,如果你想要可变集合,最好的方法是什么?简短的回答,这取决于。
性能。可变集合通常比不可变集合更快。这意味着,如果您的可变变量以某种方式包含(例如,不转义私有方法),则使用
val c = MutableCollection()
可能更好。 Collections API 中的大多数 Scala 方法在内部使用可变集合。线程安全。不可变集合的值始终是线程安全的。您可以将它发送到另一个线程,而不考虑可见性和并发更改。
var a = ImmutableCol() otherThreadProcessor.process(a) a += 1 // otherThread will still have previous value
另一方面,如果你想从多线程修改集合,最好使用Java的并发集合API。
代码清晰。想象一下,您有一些函数将集合作为参数,然后以某种方式对其进行修改。如果集合是可变的,那么在函数 returns 之后,作为参数传递的集合将保持修改状态。
def recImmutable(a:Set[Int]): Unit = { var b = a b += 4 } val a = Set(2,3) recImmutable(a) println(a) // prints Set(2, 3) def recMutable(a:mutable.Set[Int]): Unit = { var b = a b += 4 } val b = mutable.Set(2,3) recMutable(b) println(b) // prints Set(2, 3, 4)