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
如果有人有一些很好的例子 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
的目的是什么,所以问题需要更详细。
我最近开始学习 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
如果有人有一些很好的例子 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
的目的是什么,所以问题需要更详细。