Я работал над книгой «Программирование в Scala», и меня поразила небольшая проблема с реализацией класса Rational
в главе 6.
Это моя первоначальная версия класса 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