我最近开始学习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。
如果有人有一些好的例子材料(教程)来说明那些讨厌的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。
我是否需要写一个函数来解开irationals: 一个一个地拆开irationals _*并检查头部(第一个元素)的类型?
是的,你需要检查每个元素。irationals
可以包含任何子类的元素 IRational
而且它们不一定都是同一个子类型,所以你需要逐一检查。但不清楚 irationals
是,所以这个问题需要更详细。