Я недавно начал изучать Scala и сейчас возился с учебниками. Я хотел бы иметь 2 реализации рациональной арифметики. У меня есть черта IRational и 2 класса, реализующие его: Rational и RationalAbstraction. Большая часть функциональности такая же, поэтому я реализую поведение по умолчанию в трейте, но мне нужно получить правильный конструктор - либо для Rational, либо для RationalAbstraction. Для этого у меня есть функция:
def constructorImpl(numerator: Int, denominator: Int, first: IRational, irationals: IRational*): IRational = {
println(s"first class: ${first.getClass.getSimpleName}, irationals class: ${irationals.getClass.getSimpleName}")
first match {
case rational: Rational => irationals match {
case rationals: Seq[Rational] => new Rational(numerator, denominator)
case _ => throw new UnimplementedCaseException(this, "constructorImpl", first +: irationals: _*)
}
case abstraction: RationalAbstraction => irationals match {
case abstractions: Seq[RationalAbstraction] => new RationalAbstraction(numerator, denominator)
case _ => throw new UnimplementedCaseException(this, "constructorImpl", first +: irationals: _*)
}
case _ => throw new UnimplementedCaseException(this, "constructorImpl", first +: irationals: _*)
}
}
К сожалению, это не работает.
case rationals: Seq[Rational] => new Rational(numerator, denominator)
Не соответствует varargs, содержащим Rational, также позволяет RationalAbstraction.
Почему это ? Как сопоставить varargs по типу?
Нужно ли мне писать функцию, которая разворачивает ирациональные числа: _ * по одному и проверяет тип головы (первых элементов)?
Это репозиторий проекта на github: https://github.com/axal25/LearnScalaMavenBasics
Вызов тестового примера функции [256 строк]: https://github.com/axal25/LearnScalaMavenBasics/blob/master/src/main/scala/org/exercises/scala/ool/ObjectOrientedProgramming.scala
Реализация функции [106 строк]: https://github.com/axal25/LearnScalaMavenBasics/blob/master/src/main/scala/org/exercises/scala/ool/arith/ration/IRational.scala
Если у кого-то есть хороший пример материала (учебник), иллюстрирующий, как эти чертовски надоедливые варарги работают в Scala, я был бы признателен.
Изменить:
Цель метода constructorImpl
- выбрать правильный конструктор для арифматических c операций (add / +, sub / -. Mul / *, div //).
first: Irational
аргумент является 1-м аргументом операция (add, sub, mul, div).
irationals: Irational*
аргумент - это 2-й, 3-й, ... n-й аргумент операции (add, sub, mul, div).
Некоторые операции требуют 2 объекты IRational реализации, некоторые требуют 1 объект IRational impl. и, например, Int, но всегда как минимум 1 объект IRational impl. Поэтому выбор правильного конструктора зависит от этих объектов IRational impl и требует, чтобы они оба имели одну и ту же реализацию. Если 2 (или более) объекта реализации IRational имеют разную реализацию (комбинация Rational и RationalAbstraction), мы не знаем, какой конструктор вызывать, поэтому должно возникнуть исключение.
Решение в этой иерархии ( без использования дженериков):
def constructorImpl(numerator: Int, denominator: Int, first: IRational, irationals: IRational*): IRational = {
println(s"first class: ${first.getClass.getSimpleName}, irationals class: ${irationals.getClass.getSimpleName}")
@scala.annotation.tailrec
def isSeqElementsOfTypeSameAsFirst(first: Any, irationals: Any*): Boolean = irationals match {
case Seq() => true
case Seq(head, tail@_*) => {
if (first.getClass == head.getClass) isSeqElementsOfTypeSameAsFirst(first, tail: _*)
else false
}
case _ => false
}
if (isSeqElementsOfTypeSameAsFirst(first, irationals: _*)) {
first match {
case rational: Rational => new Rational(numerator, denominator)
case abstraction: RationalAbstraction => new RationalAbstraction(numerator, denominator)
case _ => throw new UnimplementedCaseException(this, "constructorImpl", first +: irationals: _*)
}
}
else throw new MixingIRationalImplementationException(first, irationals: _*)
}
фиксация вопроса: https://github.com/axal25/LearnScalaMavenBasics/commit/c5a113b0361d8632bb39bbfc7ed7f7cd329a2da1
фиксация решения: https://github.com/axal25/LearnScalaMavenBasics/commit/1920128ba2aedac4fa9671311ec56dcc09dc7483