我想在 Scala 中浅复制一个列表。
我想做这样的事情:
val myList = List("foo", "bar")
val myListCopy = myList.clone
但是克隆方法是 protected 。
最佳答案
这是一个非答案:不要那样做。一个 List
是不可变的,所以复制一个绝对没有意义。
让我们考虑几个操作:
val list = List(1,2,3)
val l1 = 0 :: list
val l2 = "a" :: list
都没有
l1
也不是 l2
正在改变 list
,但它们都创建了引用 list
的新列表.让我们详细解释一下。构造函数
List(1,2,3)
正在创建三个元素,并使用一个单例对象。具体来说,它正在实例化这些元素:::(3, Nil)
::(2, reference to the previous element)
::(1, reference to the previous element)
和
Nil
是一个单例对象。什么标识符list
实际上指向的是最后一个元素。现在,当您分配
0 :: list
时至 l1
,您正在实例化一个新对象:::(0, reference to ::(1, etc))
当然,因为有对
list
的引用,你可以想到l1
作为四个元素的列表(或五个,如果您计算 Nil
)。现在
l2
甚至不是同一类型的 list
,但它也引用了它!这里:::("a", reference to ::(1, etc))
但是,关于所有这些对象的重要一点是它们无法更改。没有 setter ,也没有任何方法可以改变它们的任何属性。它们的“头部”(这就是我们所说的第一个元素)中将永远具有相同的值/引用,并且它们的“尾部”(这就是我们所说的第二个元素)中具有相同的引用。
但是,有些方法看起来像是在更改列表。但是请放心,他们正在创建新列表。例如:
val l3 = list map (n => n + 1)
方法映射创建了一个全新的相同大小的列表,其中新元素可以从
list
中的相应元素计算出来。 (但您也可能会忽略旧元素)。val l4 = l2 filter (n => n.isInstanceOf[Int])
虽然
l4
具有与 list
相同的元素(但类型不同),它也是一个全新的列表。方法filter
根据您传递的规则创建一个新列表,告诉它哪些元素可以进入,哪些不能。它不会尝试优化,以防它可以返回现有列表。val l5 = list.tail
这不会创建新列表。相反,它只是简单地分配给
l5
list
的现有元素.val l6 = list drop 2
同样,没有创建新列表。
val l7 = list take 1
然而,这会创建一个新列表,正是因为它无法更改
list
的第一个元素。使其尾部指向 Nil
.下面是一些额外的实现细节:
List
是一个抽象类。它有两个后代,类 ::
(是的,这就是类的名称)和单例对象 Nil
. List
是密封的,所以你不能向它添加新的子类,而且 ::
是最终的,所以你不能子类化它。 关于list - 如何在 Scala 中复制列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1445629/