Scala 如何避免可变集合的意外突变?
所以,我写了一个代码来比较排序算法。我实现了几个ALG作为单独的类。这里有一些解释Scala 如何避免可变集合的意外突变?,scala,Scala,所以,我写了一个代码来比较排序算法。我实现了几个ALG作为单独的类。这里有一些解释 class BubbleSort(input:ListBuffer[Int]){ ... } class InsertionSort(input:ListBuffer[Int]){ ... } 我首先从我的驱动程序对象创建一个名为input的列表。 接下来,我将其传递给BubbleSort和InsertionSort的新实例。 然后我调用一个函数sort,它对我在对象创建过程中传递的ListBuffer进行排
class BubbleSort(input:ListBuffer[Int]){
...
}
class InsertionSort(input:ListBuffer[Int]){
...
}
我首先从我的驱动程序对象创建一个名为input
的列表。
接下来,我将其传递给BubbleSort
和InsertionSort
的新实例。
然后我调用一个函数sort
,它对我在对象创建过程中传递的ListBuffer进行排序
val input = new ListBuffer[Int]
//Populated input here
val bs = new BubbleSort(input)
val is = new InsertionSort(input)
bs.sort
is.sort
我面临的问题是,当调用is.sort
时,我在对象创建过程中传递的列表已经被排序。我想这是因为我先调用了bs.sort
,但为什么它会影响另一个类中的列表
感谢您的帮助。如果您想要更多的代码片段,我很乐意与您分享。提前谢谢
编辑
作为临时修复,我没有只创建一个列表input
,而是使用样板代码创建了两个列表,bsinput
和isinput
。然后将每个类传递给单独的类
val bsinput = new ListBuffer[Int]
val isinput = new ListBuffer[Int]
//Populated both arrays with the same data
val bs = new BubbleSort(bsinput)
val is = new InsertionSort(isinput)
bs.sort
is.sort
这解决了问题,但这是唯一的办法吗?有没有一种惯用的方法
编辑2
正如@LuisMiguelMejíaSuárez所说,这是一个参考问题。使用了
input.clone
,现在可以使用了。您将两次引用传递给同一个可变集合ListBuffer
。
这意味着您的两个排序算法将在同一个集合上工作,因此在第二次排序时,您的列表缓冲区将已经排序
为了避免意外突变,您只需在每次传递时创建一个防御副本:
val input1 = new ListBuffer[Int]
//Populated input here
val input2 = input1.clone
val bs = new BubbleSort(input1)
val is = new InsertionSort(input2)
问题是您使用的是可变数据结构。因此,由于两个类都接收相同的引用,并且它们(可能)进行了排序,那么在调用
bs.sort
之后,input
将已经被排序。您可以创建集合的副本,以便在排序之前进行排序。或者,更好的是,不要变异(至少不要改变输入),而是返回一个新的排序集合。你是对的。它们确实在适当的位置排序。所以问题是scala发送了引用而不是副本。我没有传递input
,而是传递了input.clone
。Scala像一个魔术师一样工作,只是为了澄清,它永远不会传递副本,它会传递引用,就像Java一样。在Scala上,我们通常不担心这一点,因为我们更喜欢不变性。因此,共享引用从来都不是问题,对于集合来说,这比为每次调用复制整个集合更有意义。@LuisMiguelMejíaSuárez如果我将输入作为列表传递,那么我必须在BubbleSort
中复制它(当然还有插入排序
)进入一个列表缓冲区
。因此,在一天结束时,创建的副本数量是相同的。那么,在这两种方式中,哪一种更适合scala方式呢?大多数人会认为,改变输入是“不好的”(正如您所看到的,这可能会导致意外的bug),因此我建议避免这种情况。这两种算法都可以只使用递归以函数方式编写。然而,斯卡拉不是一个纯粹的功能语言,它的能力之一(IMHO最好的一个)是它允许你使用你认为最好的风格。因此,另一种选择是在方法的局部范围上使用可变集合或带有var
(后者更安全)的不可变集合。