Scala是否优化了此代码?

时间:2012-09-06 12:39:56

标签: scala

在下面的代码中,放置query对象(在循环内或外部)的位置是否重要?为了便于阅读,我更喜欢第一个版本:

class MyClass {
  db withSession {
    names.foreach { name =>
      val query = MyEntity.createFinderBy(_.name)  <----------
      query.list(text).foreach(res =>
        doSomething
      }
    }
  }
}

但这第二版不是更好吗?

class MyClass {
  db withSession {
    val query = MyEntity.createFinderBy(_.name)  <----------
    names.foreach { name =>
      query.list(text).foreach(res =>
        doSomething
      }
    }
  }
}

甚至?

class MyClass {
  val query = MyEntity.createFinderBy(_.name)  <----------
  db withSession {
    names.foreach { name =>
      query.list(text).foreach(res =>
        doSomething
      }
    }
  }
}

在Java中,我会把它放在类顶部的静态final字段中......

2 个答案:

答案 0 :(得分:2)

不,它没有,因为在第一个例子中,你特意告诉它为每个元素调用createFinderBy(以及list)。不能保证这些方法每次都会返回相同的值(即引用透明),因此值不能被记忆或者代码被优化为第二或第三实例

如果您可以对方法进行注释,或者编译器可以解决这个问题,那么这将是一个很好的功能,但目前还没有。

另外,您可以更改createFinderBy方法,以便将值存储在mutable.Map缓存中,并使用getOrElseUpdate方法返回值,如果您的查询返回缓存值已经在地图中,或者计算查询并缓存它。

答案 1 :(得分:2)

scalac不会(不能)优化您的代码,因为它不使用效果系统。这使得scalac几乎不可能关心优化是否会破坏代码。例如,如果MyEntity.createFinderBy(_.name)不纯(可能会增加一个计数访问次数的计数器),如果执行一次或每次迭代,它将进行更改。

在这种情况下,我可以建议更改函数文字的位置:

scala> 1 to 3 foreach {x => println("x"); println(x)}
x
1
x
2
x
3

scala> 1 to 3 foreach {println("x"); x => println(x)}
x
1
2
3

在第二个例子中,创建了一个返回传递给foreach的函数的块(在执行其他表达式之后),而在前者中,整个块是一个函数。