Max*_*ime 12 scala copy list shallow-copy
我想浅谈Scala中的列表.
我想做像:
val myList = List("foo", "bar")
val myListCopy = myList.clone
Run Code Online (Sandbox Code Playgroud)
但克隆方法受到保护.
Dan*_*ral 14
这是一个非答案:不要这样做.A List是不可变的,所以复制一个绝对没有意义.
让我们考虑一些操作:
val list = List(1,2,3)
val l1 = 0 :: list
val l2 = "a" :: list
Run Code Online (Sandbox Code Playgroud)
既不改变l1也不l2改变list,但它们都创建了引用的新列表list.
我们来详细解释一下.构造函数List(1,2,3)创建了三个元素,并使用单例对象.具体来说,它是实例化这些元素:
::(3, Nil)
::(2, reference to the previous element)
::(1, reference to the previous element)
Run Code Online (Sandbox Code Playgroud)
并且Nil是一个单身对象.标识符list实际指向的是最后一个元素.
现在,当您分配0 :: list时l1,您正在实例化一个新对象:
::(0, reference to ::(1, etc))
Run Code Online (Sandbox Code Playgroud)
当然,既然有一个参考list,你可以把它想象l1成四个元素的列表(如果你算的话,可以算是五个元素Nil).
现在l2甚至不是同一类型list,但它也引用它!这里:
::("a", reference to ::(1, etc))
Run Code Online (Sandbox Code Playgroud)
然而,关于所有这些对象的重点是它们不能被改变.没有setter,也没有任何方法可以改变它们的任何属性.它们将永远在它们的"头部"(我们称之为第一个元素)中具有相同的值/引用,并且在它们的"尾部"中具有相同的引用(这就是我们称之为第二个元素).
但是,有些方法看起来正在改变列表.但请放心,他们正在创建新列表.例如:
val l3 = list map (n => n + 1)
Run Code Online (Sandbox Code Playgroud)
方法映射创建一个相同大小的全新列表,其中可以从相应的元素中计算新元素list(但您也可以忽略旧元素).
val l4 = l2 filter (n => n.isInstanceOf[Int])
Run Code Online (Sandbox Code Playgroud)
虽然l4具有与list(但是不同类型)相同的元素,但它也是一个全新的列表.该方法filter根据您传递的规则创建一个新列表,告诉它哪些元素进入,哪些元素不进入.如果它可以返回现有列表,它不会尝试优化.
val l5 = list.tail
Run Code Online (Sandbox Code Playgroud)
这不会创建新列表.相反,它只是分配给l5现有的元素list.
val l6 = list drop 2
Run Code Online (Sandbox Code Playgroud)
同样,没有创建新列表.
val l7 = list take 1
Run Code Online (Sandbox Code Playgroud)
但是,这会创建一个新列表,正是因为它无法更改list其尾部指向的第一个元素Nil.
这里有一些额外的实现细节:
List是一个抽象类.它有两个后代,类::(是的,这是类的名称)和单例对象Nil.List是密封的,所以你不能添加新的子类,并且::是最终的,所以你不能将它子类化.
虽然您无法执行任何更改列表的操作,但在某些操作中它会在内部使用可变状态.这有助于提高性能,但它是本地化的,因此您编写的程序无法检测到它,或者受其影响.您可以根据需要传递列表,无论其他函数对它们执行什么操作,或者有多少线程同时使用它们.
小智 6
要过滤列表:
val list = List(1,2,3,4,5)
//only evens
val evens = list.filter(e=>e%2 == 0)
println(list)
//--> List(1, 2, 3, 4, 5)
println(evens)
//--> List(2, 4)
Run Code Online (Sandbox Code Playgroud)
您还可以使用通配符来保存几个字符:
val evens = list.filter(_%2==0)
Run Code Online (Sandbox Code Playgroud)
请注意,如上所述,列表是不可变的.这意味着这些操作不会修改原始列表,但实际上会创建一个新列表.