Scala: 根据存储元素的类型匹配vararg(重复参数)。

问题描述 投票:0回答:1

我最近开始学习Scala,目前正在乱看教程。我想有两个Rational Arithmetics的实现。我有特质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的varargs,也允许RationalAbstraction。为什么会这样?如何按类型匹配varargs?我是否需要写一个函数来拆开irationals: _*并检查头部(第一个元素)的类型?

这是项目的github仓库。https:/github.comaxal25LearnScalaMavenBasics。

调用函数测试用例[256行]。https:/github.comaxal25LearnScalaMavenBasicsblobmastersrcmainscalaorgexercisesscalaoolObjectOrientedProgramming.scala。

函数实现[106行]。https:/github.comaxal25LearnScalaMavenBasicsblobmastersrcmainscalaorgexercisesscalaoolarithrationIRational.scala。

如果有人有一些好的例子材料(教程)来说明那些讨厌的varargs在Scala中是如何工作的,我会很感激。

编辑: 在Scala中的 constructorImpl 方法是为算术运算(add+, sub. mul*, div/)选择正确的构造函数。first: Irational 参数是运算的第1个参数(加法,子法,乘法,除法)。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.comaxal25LearnScalaMavenBasicscommitc5a113b0361d8632bb39bbfc7ed7f7cd329a2da1。 解决方案提交。https:/github.comaxal25LearnScalaMavenBasicscommit1920128ba2aedac4fa9671311ec56dcc09dc7483。

scala types arguments repeat variadic-functions
1个回答
0
投票

我是否需要写一个函数来解开irationals: 一个一个地拆开irationals _*并检查头部(第一个元素)的类型?

是的,你需要检查每个元素。irationals 可以包含任何子类的元素 IRational 而且它们不一定都是同一个子类型,所以你需要逐一检查。但不清楚 irationals 是,所以这个问题需要更详细。

© www.soinside.com 2019 - 2024. All rights reserved.