如何初始化要在另一个范围内使用的val?在下面的示例中,我被迫将myOptimizedList
作为var,因为它在if (iteration == 5){}
范围内初始化并在if (iteration > 5){}
范围内使用。
val myList:A = List(...)
var myOptimizedList:A = null
for (iteration <- 1 to 100) {
if (iteration < 5) {
process(myList)
} else if (iteration == 5)
myOptimizedList = optimize(myList)
}
if (iteration > 5) {
process(myOptimizedList)
}
}
可能会问before,但我想知道是否有一个使用Option [A]的优雅解决方案。
答案 0 :(得分:8)
似乎您已从上下文中获取此代码示例,因此此解决方案可能不太适合您的真实上下文,但您可以使用foldLeft
来简化它:
val myOptimizedList = (1 to 100).foldLeft (myList) {
case (list, 5) => optimize(list)
case (list, _) => process(list); list
}
答案 1 :(得分:3)
您几乎总是可以将某种循环结构重写为(尾部)递归函数:
@annotation.tailrec def processLists(xs: List[A], start: Int, stop: Int) {
val next = start + 1
if (start < 5) { process(xs); processLists(xs, next, stop)
else if (start == 5) { processLists( optimize(xs), next, stop) }
else if (start <= stop) { process(xs); processLists( xs, next, stop ) }
}
processLists(myList, 100, 1)
在这里,您传递了原本会发生变异的数据。如果你需要改变大量的东西,它会变得笨拙,但对于一两个,它通常比变异更清楚或更清楚。
答案 2 :(得分:2)
通常情况下,您可以重新编写代码以避免出现问题。在这里考虑一个简单而常见的例子:
var x = 0
if(something)
x = 5
else
x = 6
println(x)
在大多数语言中,这将是一种非常常见的模式,但Scala有更好的方法。具体来说,if语句可以返回值,因此更好的方法是:
val x =
if(something)
5
else
6
println(x)
所以我们毕竟可以使x
成为一个val。
现在,显然您的代码可以重写为使用所有val
s:
val myList:A = List(...)
for (iteration <- 1 to 5)
process(myList)
val myOptimizedList = optimize(myList)
for (iteration <- 5 to 100)
process(myOptimizedList)
但我怀疑这只是一个例子,而不是你的真实案例。但如果您不确定如何重新排列实际代码以完成类似的操作,请告诉我们它的外观。
答案 3 :(得分:2)
还有另一种技术(在这种情况下可能是技巧)来延迟初始化
myOptimizedList
这是使用懒惰的val。您的示例非常具体,但主体仍然很明显,延迟分配val直到它首次被引用。
val myList = List(A(), A(), A())
lazy val myOptimizedList = optimize(myList)
for (iteration <- 1 to 100) {
if (iteration < 5)
process(myList)
else if (iteration > 5)
process(myOptimizedList)
}
请注意,案例iteration == 5
会被忽略。