关于集合:scala 附加到可变的 LinkedList

scala append to a mutable LinkedList

请检查这个

1
2
3
4
5
6
7
8
9
import scala.collection.mutable.LinkedList

var l = new LinkedList[String]

l append LinkedList("abc","asd")

println(l)
// prints
// LinkedList()

但是

1
2
3
4
5
6
7
8
9
10
import scala.collection.mutable.LinkedList

var l = new LinkedList[String]

l = LinkedList("x")
l append LinkedList("abc","asd")

println(l)
// prints
// LinkedList(x, abc, asd)

为什么第二个代码片段有效,而第一个无效?这是在 Scala 2.10


文档说 If this is empty then it does nothing and returns that. Otherwise, appends that to this.。这正是你观察到的。如果你真的需要一个可变列表,我建议你使用 scala.collection.mutable.ListBuffer 代替,你可以这样做

1
2
3
4
5
6
7
8
9
10
11
12
13
val lb = new ListBuffer[Int]

scala> lb += 1
res14: lb.type = ListBuffer(1)

scala> lb
res15: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1)

scala> lb ++= Seq(1,2,3)
res17: lb.type = ListBuffer(1, 1, 2, 3, 1, 2, 3)

scala> lb
res18: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 1, 2, 3, 1, 2, 3)


据我了解,它与列表中的第一个/最后一个 (Nil) 元素有关(如果列表为空 Nil 同时是第一个和最后一个元素)。

LinkedList(仍然)遵循"原始魅力"策略。因此它不会尝试在 Nil 之后添加/追加新数据,从而可能产生如下结果:{Nil, newElement}。 (毕竟 Nil 应该是最后一个元素)

当然可以检查if列表是否为空,然后将addingList放在开头,Nil放在结尾。但这将是"太聪明了",我猜。

但是,无论如何 append() 返回"预期"结果就像这样:

1
2
val addingList = new LinkedList[String]("a","b")
val result = emptyList append addingList

result = {"a","b"}. 在这种情况下,它会返回 'addingList' 本身,并且/但不会更改初始列表。

如果我们尝试将 newElement 分配给 next ref:

1
   emptyList.next = LinkedList("whatever")

因此,我们将 emtyList 更改为:

1
 LinkedList(null, whatever)

即它将第一个元素创建为 null,因为我们使用 next() 为其分配新/下一个元素。所以它将 Nil 移动到最后,因为第一个为 null 的元素具有对我们添加的新元素 (addingElelement) 的下一个引用。

因为

"the"emptyList" is also the"head" link"

和 head 在我们的例子中 head 是 Nil,但是 Nill 不能有下一个,所以它必须创建新的第一个元素(它具有空值), next() 引用我们的新 addingElelement

我个人觉得它"太原始"而不是"那么优雅"。但这取决于,我猜。

以任务为导向的故事:

对于我的初始任务(为什么我开始考虑这种"奇怪"的列表行为[即使它是可变的])——我想为一个名为 Dictionary 的类/对象使用可变列表,它会保留 Words它(字典默认没有任何单词)。我会有像 addWord(wod:String) 这样的方法来添加新词。现在我的实现将被更改(我不会使用这个 LinkedList,而是使用 MutableList。它似乎比以前的更易变):

1
2
3
4
5
6
7
8
9
object Dictionary {

  val words = new mutable.MutableList[Word]();

  def addWord(word: Word): Unit = {
    words += word;
  }

}

但可能的实现可能是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
object Dictionary {

  var words = new mutable.LinkedList[Word]();

  def addWord(word: Word): Unit = {

    if (words.isEmpty) {
      words = words append( mutable.LinkedList[Word](word) ) // rely on append result
    } else {
      words append( mutable.LinkedList[Word](word) )
    }

  }

}

但后来我必须用var而不是val,而且我要把每一个新词都转换成LinkedList,我的逻辑变得更复杂了。