我正在阅读Scala 编程"一书,但在第 6 章中实现类 Rational 时遇到了一个小问题.
I was working through the "Programming in Scala" book, and was struck by a bit of a problem in the implementation of the class Rational in Chapter 6.
这是我的 Rational 类的初始版本(基于本书)
This is my initial version of the Rational class (based on the book)
class Rational(numerator: Int, denominator: Int) { require(denominator != 0) private val g = gcd(numerator.abs, denominator.abs) val numer = numerator / g val denom = denominator / g override def toString = numer + "/" + denom private def gcd(a: Int, b: Int): Int = if(b == 0) a else gcd(b, a % b) // other methods go here, neither access g }这里的问题是字段 g 在类的整个生命周期中都会保留,即使再也不会被访问.这个问题可以通过运行下面的模拟程序看到:
The problem here is that the field g remains for the lifetime of the class, even if never again accessed. This problem can be seen by running the following mock program:
object Test extends Application { val a = new Rational(1, 2) val fields = a.getClass.getDeclaredFields for(field <- fields) { println("Field name: " + field.getName) field.setAccessible(true) println(field.get(a) + "\n") } }它的输出将是:
Field: denom 2 Field: numer 1 Field: g 1我在 Scala Wiki 上找到的解决方案涉及以下内容:
A solution I found at the Scala Wiki involves the following:
class Rational(numerator: Int, denominator: Int) { require(denominator != 0) val (numer, denom) = { val g = gcd(numerator.abs, denominator.abs) (numerator / g, denominator / g) } override def toString = numer + "/" + denom private def gcd(a: Int, b: Int): Int = if(b == 0) a else gcd(b, a % b) // other methods go here }此处,字段 g 仅在其块的本地,但是,运行小型测试应用程序时,我发现了另一个字段 x$1,它保留了由 (numer, denom)!
Here, the field g is only local to its block, but, running the small test application, I found another field x$1 which keeps a copy of the tuple consisting of (numer, denom)!
Field: denom 2 Field: numer 1 Field: x$1 (1,2)有没有什么办法可以用上面的算法在Scala中构造一个有理数,而不会造成任何内存泄漏?
Is there any way to construct a rational in Scala with the above algorithm, without causing any memory leaks?
谢谢,
弗拉维乌·西皮根
推荐答案你可以这样做:
val numer = numerator / gcd(numerator.abs, denominator.abs) val denom = denominator / gcd(numerator.abs, denominator.abs)当然,您必须进行两次计算.但是优化通常是内存/空间和执行时间之间的权衡.
Of course you'd have to do the calculation twice. But then optimizations are often a trade-off between memory/space and execution time.
也许还有其他方法,但是程序可能会变得过于复杂,如果有一个地方的优化很少为时过早,那就是脑力优化:).例如,您可能可以这样做:
Maybe there are other ways too, but then the program might get overly complex, and if there's one place where optimization is rarely premature, it's brain power optimization :). For instance, you could probably do this:
val numer = numerator / gcd(numerator.abs, denominator.abs) val denom = denominator / (numerator / numer)但这并不一定会使代码更易于理解.
But it doesn't necessarily make the code more understandable.
(注意:我实际上没有尝试过,所以使用风险自负.)
(Note: I didn't actually try this, so use at your own risk.)
更多推荐
避免 Scala 内存泄漏
发布评论