我正在阅读《Scala编程》这本书,但在第6章实现Rational
类时遇到了一些问题。
这是我根据书中内容编写的Rational
类的初始版本。
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仍然存在于类的生命周期中。可以通过运行以下模拟程序来看到这个问题:
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上找到了一种解决方案,具体如下:
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)
的元组的副本!
Field: denom
2
Field: numer
1
Field: x$1
(1,2)
有没有办法使用上述算法在Scala中构建一个有理数,而不会导致任何内存泄漏?
谢谢,
Flaviu Cipcigan
denom
和numer
是真正的值吗?如果它们只是形如def denom = x$1._2
的访问器方法,我一点也不会感到惊讶。 - Raphael