我只想弄清楚像List这样的不可变的东西是如何工作的,以及我如何向它添加东西?
我很遗憾地问这些愚蠢的问题,但是为什么我的列表在打印出来时总是空的?
var end = false
val list = List()
while (!end) {
val input = scala.io.StdIn.readLine("input:")
if (input == "stop" ) end = true
else input :: list
}
println(list)
}
对于我的不便和这个相当愚蠢的问题感到抱歉!
答案 0 :(得分:6)
我只想弄清楚像List这样的不可变的东西是如何工作的,以及我如何向它添加东西?
你不能。毕竟, immutable 意味着什么。如果拉丁文不是你的一杯茶, immutable 的英文翻译是不可更改的。现在应该清楚,为什么你不能改变不可改变的东西。
我很遗憾地问这些愚蠢的问题,但是为什么我的列表在打印出来时总是空的?
您创建一个空列表,并且永远不会更改它(因为它无法无论如何都要更改)。所以,当然是空的。
可以做什么,但是,创建新列表几乎与旧列表完全相同项目前置于前面。这就是你在这里做的事情:
input :: list
但是,你不能在任何地方分配这个新列表,你不会将其归还,你完全忽略它。
如果您想以任何方式实际使用您的列表,您需要以某种方式记住它。最明显的解决方案是将其分配给变量:
var end = false
var list: List[String] = List() // note: `var` instead of `val`
while (!end) {
val input = scala.io.StdIn.readLine("input:")
if (input == "stop" ) end = true
else list = input :: list // note: assign to `list`
}
println(list)
但是,这不是很惯用。毕竟,我们现在已经使用 immutable 列表并将其分配给 mutable 变量......现在,我们刚刚改变了可变性。
相反,我们可以使用递归解决方案:
def buildListFromInput(list: List[String] = List()): List[String] = {
val input = scala.io.StdIn.readLine("input:")
if (input == "stop") list else buildListFromInput(input :: list)
}
println(buildListFromInput())
这个解决方案不仅是递归的,递归调用也在尾部位置(IOW,方法是尾递归),这意味着它只是与while
循环一样高效(事实上,它将被编译为while
循环,或者更确切地说,编译为GOTO
循环。 Scala语言规范保证Scala 的所有实现必须消除直接尾递归。
答案 1 :(得分:2)
原因
println(list)
只打印出一个空列表是因为位
input :: list
实际上并没有改变列表本身。在这种情况下,它只是暂时的,创建一个包含前面输入的列表。
尝试
println(input :: list)
或
val newList = input :: list
println(newList)
你会明白我的意思。
答案 2 :(得分:1)
在scala中,List是不可变的。
当您添加要列出的项目时,新的List
实例将以项目为首,其尾部现在包含上一个列表。
如果您在内部有名为intList
的“1,2,3”列表,则表示为
列表(3,列表(2,列表(1,无)))
如果您向此4
intList
List(4,intList)
让我们称之为newList
注意 intList
仍然包含List(3, List(2, List(1, Nil) ) )
。
如果您希望intList
引用newList
,则必须执行
intList = intList.add(4)
将列表从val
更改为var
。然后,您可以将结果列表分配给list
变量
list = input :: list
来源:Scala在线课程名为Functional Programming Principles in Scala
答案 3 :(得分:1)
尝试以更多功能方式重写代码。不可变数据结构上的每个操作都会返回带有更改的新实例。因此,::
运营商会在前面创建包含input
的新列表。您可能希望尝试将此代码重写为尾递归函数,如下所示。
@tailrec
def scanInput(continue: Boolean,acc: List[String]): List[String] = {
val input = scala.io.StdIn.readLine("input:")
if(!continue) acc
else scanInput(input != "stop", input :: acc)
}
上面的代码没有变异状态,它适合更多Scala功能样式。
答案 4 :(得分:0)
感谢您的帮助,感谢大家的帮助! 我应该仔细看看递归,因为它似乎非常重要,就像在Scala中一样! 但是,通过你的帮助,我会更好地了解它是如何工作的!
我只是想弄清楚你的解决方案是如何工作的并创建了我自己的解决方案:
val list = List()
def scanInput(acc: List[String]): List[String] = {
val input = scala.io.StdIn.readLine("input:")
input match {
case "stop" => acc
case _ => scanInput(input :: acc)
}
}
println(scanInput(list))