我有一些样板文件的 Scala 代码,我认为它是 Scala,所以我一定做错了什么。我需要一些帮助来弄清楚如何删除冗余。
trait Number {
val x: Int
}
case class EvenNumber(x: Int) extends Number
object EvenNumber {
def unapply(s: String): Option[EvenNumber] = {
val x = s.toInt
if (x % 2 == 0) Some(EvenNumber(x))
else None
}
}
case class OddNumber(x: Int) extends Number
object OddNumber {
def unapply(s: String): Option[OddNumber] = {
val x = s.toInt
if (x % 2 == 1) Some(OddNumber(x))
else None
}
}
在这个简单的示例中,有偶数和奇数,它们是一般数字类型的子类型。偶数和奇数都有提取器,可以从字符串中创建它们。这启用了以下用例。
scala> "4" match {case EvenNumber(n) => n;case _ => None}
// returns EvenNumber(4)
scala> "5" match {case EvenNumber(n) => n;case _ => None}
// returns None
scala> "4" match {case OddNumber(n) => n;case _ => None}
// returns None
scala> "5" match {case OddNumber(n) => n;case _ => None}
// returns OddNumber(5)
x % 2
除了运算结果 ( 0
or 1
) 和提取类型 ( EvenNumber
or )之外,这两个提取器的源代码是相同的OddNumber
。我希望能够编写一次源代码并对这两个值进行参数化,但我不知道如何。我尝试了各种类型参数化无济于事。
Stackoverflow 问题“ How to use extractor in polymorphic unapply? ”是相关但不同的,因为我的实现类不是通过它们包含的类型来区分,而是通过它们识别的字符串输入来区分。
这是代码的修订版本,除了原始帖子之外,还包含我收到的评论。(通常情况下,第一轮答案帮助我弄清楚我真正的问题是什么。)
import scala.util.Try
trait Number {
val x: Int
}
object NumberParser {
def parse[N <: Number](s: String, remainder: Int, n: Int => N): Option[N] =
Try {s.toInt}.toOption.filter(_ % 2 == remainder).map(n(_))
}
case class EvenNumber(x: Int) extends Number
object EvenNumber {
def unapply(s: String): Option[EvenNumber] = NumberParser.parse(s, 0, EvenNumber(_))
}
case class OddNumber(x: Int) extends Number
object OddNumber {
def unapply(s: String): Option[OddNumber] = NumberParser.parse(s, 1, OddNumber(_))
}
分解出一个静态NumberParser.parse
函数是一个合理的解决方案。我仍然希望有语法糖来消除我unapply
在所有案例类中的重复行,因为在一个更复杂的示例中,有两个以上可能会变得丑陋。有谁知道这样做的方法?
更关键的是,我真正想要支持的用例如下。
scala> "5" match {case EvenNumber(n) =>n;case OddNumber(n) => n;case _ => None}
// returns OddNumber(5)
scala> "4" match {case EvenNumber(n) =>n;case OddNumber(n) => n;case _ => None}
// returns EvenNumber(4)
scala> "x" match {case EvenNumber(n) =>n;case OddNumber(n) => n;case _ => None}
// returns None
同样,这对于两种情况都很好,但在有两个以上的不同应用程序中,它可能变得难以管理。我想写一个案例
s match {case Number(n) => n; case _ => None}
它返回OddNumber(5)
, EvenNumber(4)
,None
如上。我不知道如何编写我的Number
超类型来支持这一点。斯卡拉有可能吗?
编辑:在“使用 Scala 提取器的运行时多态性”中写了我的最终答案的描述以及附加评论。