Scala:按存储元素的类型匹配可变参数(重复参数)

Scala: Matching vararg (repeating arguments) by type of stored elements

我最近开始学习 Scala,目前正在研究教程。我想要 Rational Arithmetics 的 2 个实现。我有特征 IRational 和 2 类 实现它:Rational 和 RationalAbstraction。大多数功能是相同的,所以我在 trait 中实现了默认行为,但我需要获得正确的构造函数——无论是对于 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)
不匹配包含 Rational 的可变参数,也允许 RationalAbstraction。
这是为什么? 如何按类型匹配可变参数?
我是否需要编写一个函数来解开有理数:_* 并检查头部(第一个元素)的类型?

这是项目 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

如果有人有一些很好的例子 material(教程)说明那些该死的讨厌的 varargs 如何在 Scala 中工作,我将不胜感激。

编辑:
constructorImpl 方法的目的是为算术运算选择正确的构造函数 (add/+, sub/-.mul/*, div//).
first: Irational 参数是操作的第一个参数(add、sub、mul、div)。
irationals: Irational* 参数是操作的第 2、3、...第 n 个参数(add、sub、mul、div)。
有些操作需要 2 个 IRational 实现对象,有些需要 1 个 IRational 实现对象。例如 Int,但始终至少有 1 个 IRational impl 对象。因此,选择正确的构造函数取决于那些 IRational impl 对象,并且要求它们都具有相同的实现。如果 IRational 实现的 2 个(或更多)对象具有不同的实现(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

Do I need to write function that unwraps irationals: _* one by one and check the head's (first elements') type?

是的,您需要检查每个元素。 irationals 可以包含 IRational 的任何子类的元素,并且它们不必都是相同的子类型,因此您需要检查每一个。但不清楚irationals的目的是什么,所以问题需要更详细。