Я новичок в Scala. Следующий код является моим продолжением первого урока из курса «Принципы функционального программирования в Scala» профессора Мартина Одерского из первого урока о Rationals «Функции и данные».
Я добавил opti
метод, который делит знаменатель и знаменатель на их наибольший общий делитель (gcd
), например, делает 2/4 равным 1/2. Но ради интереса я решил добавить возможность добавления автоматической оптимизации после каждого вызова add
и Sub
(на этот раз забудьте о производительности). Поэтому я могу написать метод makeOptiAuto(Boolean): Unit
, но для этого потребуется оператор if в каждом методе and
/ sub
. Поэтому я решил создать класс с именем OptimalizedRational
, который будет вызывать opti
в конце каждого
and
/ sub
вызов.
Проблема в том, что я сделал это как расширение моего класса Rational. Может быть, это должен быть его член (Rational.OptimaliyedRational
)?
Во-вторых, я должен вызвать конструктор Rational. Это необходимо в этом случае? На самом деле, я переопределяю их, поэтому конструктор Rational бесполезен. Я могу назвать gcd как extends Rational(gcd(x, y) / x, gcd(x, y) / y)
, но это то же самое значение. Так что я должен использовать val. Можно ли вызвать Rational
конструктор, используя gcd
только один раз? Как лучше всего выполнять такую работу?
Другая проблема заключается в add
/ sub
методах. Если я хочу вызвать метод с помощью super, то мне возвращается объект Rational
, поэтому, если я хочу вернуть OptimalizedRational
, мне нужно снова использовать optiAuto ... Может быть, я должен использовать asInstanceOf[Rational]
для его приведения, но сначала он не работает (выдается ошибка), а во-вторых, он медленный (Java выполняет динамическое приведение, если я не ошибаюсь).
Итак, кто будет смотреть хорошо написанный код Scala, который делает то, что я пытался сделать? Может кто-то отправил исправленную версию с некоторыми пояснениями?
код:
object Learning {
// IMMPLEMENTATION OF `Rational` CLASS:
class Rational(x: Int, y: Int) {
def nom = x
def denom = y
def add(that: Rational): Rational =
new Rational((nom*that.denom + that.nom*denom), (denom*that.denom))
def neg: Rational =
new Rational(-nom, denom)
def sub(that: Rational): Rational =
add(that.neg)
// used by opti() and for OptimalizedRational
protected def gcd(a: Int, b: Int): Int =
if (b == 0) a
else gcd(b, a % b)
def opti(): Rational = {
val d = gcd(nom, denom)
new Rational(nom / d, denom / d)
}
// shorthand methods:
def add(a: Int, b: Int): Rational = add(new Rational(a, b))
def sub(a: Int, b:Int): Rational = sub(new Rational(a, b))
// OptimalizedRational immplementation (between classes):
def optiAuto() = new OptimalizedRational(nom, denom)
def isOpti = false
// others:
override def toString = { opti(); nom + "/" + denom }
}
class OptimalizedRational(x: Int, y: Int) extends Rational(x, y) {
// constructor:
val d = gcd(x, y)
override def nom = x / d
override def denom = y / d
// basic behaviour via method overriding:
override def add(a: Int, b: Int) = super.add(a, b).opti().optiAuto()
override def sub(a: Int, b: Int) = super.sub(a, b).opti().optiAuto()
// OptimalizedRational immplementation (between classes):
def optiNoAuto() = new Rational(nom, denom)
override def isOpti = true
}
// TESTING:
new Rational(2, 3).optiAuto().add(1, 2).sub(3, 4)
new Rational(10, 24).opti().toString()
new OptimalizedRational(10, 24).toString()
new Rational(10, 24).toString()
}