我怎样才能修改Nil列表?

时间:2010-12-18 01:44:30

标签: scala

你知道在再见和感谢所有的鱼中的那个场景,亚瑟非常高兴,他停下了服务员并要求知道,“为什么这种食物如此美味?”我处于那种情况。 Scala似乎正在做我想要的,但我不明白它是如何做到的。请考虑以下事项:

scala> var v = Nil:List[String];
v: List[String] = List()

scala> v.length
res38: Int = 0

scala> v ::= "Hello"

scala> v.length
res39: Int = 1

scala> Nil.length
res40: Int = 0

这正是你所希望的,但它是如何发生的?

Nil是扩展List [Nothing]的对象,它是List [String]的子类型,所以赋值工作正常,但它是 immutable 列表,不是吗?所以我不应该追加它。但是我可以附加它,或者至少我可以附加到v,我认为它指向Nil。 v被改变了,但是Nil不是。

那么,WTF? Scala是否有一些我不知道的聪明的复制修改语义? Nil真的是一个返回空列表的函数吗?更广泛地说,有什么方法可以让REPL回答这些问题吗?

4 个答案:

答案 0 :(得分:16)

当Scala看到

v ::= "Hello"

首先检查v是否知道方法::=。在这种情况下(类型List),它不会,因此,因为该方法仅由符号组成,并以=符号结束,它会尝试其他内容:< / p>

v = v.::("Hello")

顺便提一下,用中缀表示法写成"Hello" :: v。现在,由于v知道方法::,该方法有效,并返回一个新的List,然后按照指示将其分配给v

顺便说一下,它是在前置,而不是附加。

答案 1 :(得分:4)

当您使用关键字var时,您并非“在Java意义上”转换为final“。相反,var允许重新分配。当您致电运营商::=时,您实际上正在重新分配v指向的内容。运算符::=返回 new 列表,而不是附加“Hello”的原始列表。因此,v现在指向“Hello”而不是Nil列表。

在这里,请注意:

var myThing = new List(1, 2, 3)
var myOhterThing = myThing

myThing = new List(1, 2, 3, 4)

这与说“获取第一个列表,复制它并在其上附加'4'几乎相同。现在指定'myThing'指向该列表。”使用该运算符,您可以有效地完成相同的操作。用这种方式写出来可以让你看到它。

答案 2 :(得分:3)

尝试使用val v,看看哪些是可变的。 :)

答案 3 :(得分:2)

Nil是不可改变的。当你对它(... :)有所了解时,你会得到一个也是不可变的新实例。

试试这个:

val v1 = Nil
val v2 = "Hello" :: v1
v1 == v2 

(因为他们没有指向同一个对象,你会得到假的)

鉴于v是一个var,你可以为它重新分配值。

所以当你有:

v ::= "Hello" // what you really have is:
v = "Hello" :: v  // or
v = "Hello" :: Nil // or
v = List("Hello")

以上创建了一个新List,Nil保持不变。它类似于Java中的String添加。由于String是不可变的,因此您永远不会更改单个实例 - 只创建新实例。

由于Nil没有改变,Nil.length = 0。