在下面的代码中,放置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字段中......
答案 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的函数的块(在执行其他表达式之后),而在前者中,整个块是一个函数。