初始化要在不同范围内使用的val

时间:2012-02-02 20:10:17

标签: scala

如何初始化要在另一个范围内使用的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]的优雅解决方案。

4 个答案:

答案 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会被忽略。