我正在尝试学习使用Scala的各种可能性来创建DSL的良好做法,但是我遇到了以下问题:我无法创建适用于Iterable的所有子类型(数组,列表, ...),并且仅匹配我定义的特定类型的子类型(在示例中:Fruit)。到目前为止,这是我想出的(这是我的代码的简化版本):
sealed trait Fruit { // My main type
type A <: Fruit
def setSize(v: Int): Unit = this match {
case multi: MultiFruit[_] => multi.foreach(_.setSize(v))
case or: Orange => or.size = v
case ap: Apple => ap.size = v
case _ => throw new Exception
}
}
case class MultiFruit[F <: Fruit](var l: List[F]) extends Fruit {
type A = F
def foreach[B](f: F => B) : Unit = l.foreach(f)
}
case class Orange(var size: Int) extends Fruit {
type A = Orange
}
case class Apple(var size: Int) extends Fruit {
type A = Apple
}
object Fruit {
implicit class IterableFruit[F <: Fruit, I <: Iterable[F]](val ite: I) extends AnyVal {
def setSize(v: Int): Unit = ite.foreach(_.setSize(v)) // Apply setSize on every Fruit of the iterable
def ++[F2 <: Fruit, I2 <: Iterable[F2]](ite2: I2): MultiFruit[_ <: Fruit] = new MultiFruit[Fruit](ite.toList++ite2.toList)
}
}
所以这是我的问题:当我尝试运行此程序时
object Main {
import Fruit._
def main(args: Array[String]): Unit = {
val oranges = Array.tabulate(5)(i => Orange(i*10))
val apples = Array.tabulate(5)(i => Apple(i*10))
oranges setSize 20 // setSize is not found, it doesn't match Iterable[Fruit]
val or_ap = oranges ++ apples // ++ not found (the compiler wants to use the one defined in Array)
}
}
找不到我的方法setSize和++。更让我感到困惑的是,我的IDE(IntelliJ)发现了setSize方法(并且没有报告任何错误),但IDE认为++是在Array中定义的,而不是在我的隐式类中定义的。我认为我的问题出在我键入IterableFruit类的方式上,但是我在扩展方法上发现的资源非常有限(而且从来没有真正深入过),而且我不知道出了什么问题。
编辑:另外,当我将隐式类修改为:
object Fruit {
implicit class IterableFruit[F <: Fruit](val ite: Array[F]) extends AnyVal {
def setSize(v: Int): Unit = ite.foreach(_.setSize(v)) // Apply setSize on every Fruit of the iterable
def ++[F2 <: Fruit](ite2: Array[F2]): MultiFruit[_ <: Fruit] = new MultiFruit[Fruit](ite.toList++ite2.toList)
}
}
一切都编译了,但是现在如果我尝试使用其他可迭代的变量而不是数组,显然就行不通了,所以我认为问题确实来自于我在隐式类中键入的方式
这可以通过将数组变成可迭代的方式来解决:
val oranges = Array.tabulate(5)(i => Orange(i*10)).toIterable