1

在下面的代码中,我将对象放在哪里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中,我会将它放在类顶部的静态最终字段中......

4

2 回答 2

2

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

如果您可以这样注释方法,或者如果编译器可以解决它,那将是一个很好的功能,但目前它没有。

顺便说一句,您可以更改该createFinderBy方法,使其将值存储在mutable.Map缓存中并使用该getOrElseUpdate方法返回值,如果您的查询已经在地图中,则该方法返回一个缓存值,否则计算查询并缓存它。

于 2012-09-06T13:59:16.310 回答
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 的函数的块(在执行其他表达式之后),而在前一个示例中,整个块是一个函数。

于 2012-09-06T13:59:41.563 回答