让我们有课程Fruit
,Orange
和Apple
。
abstract class Fruit
class Orange extends Fruit
class Apple extends Fruit
现在,我想为write
和Orange
两种类型添加Apple
功能。使用类型类模式,我可以执行以下操作:
trait Writer[T] {def write(t:T)}
implicit object AppleWriter extends Writer[Apple] {
def write(a:Apple) {println("I am an apple!")}
}
implicit object OrangeWriter extends Writer[Orange] {
def write(o:Orange) {println("I am an orange!")}
}
def write[T](t:T)(implicit w:Writer[T]){w.write(t)}
所以,非常好,但如果我想定义writeFruits
怎么办?
def writeFruits(fruits:List[Fruit]) {for (fruit <- fruits) write(fruit)}
我希望writeFruits
为每个write[Apple]
拨打write[Orange]
或fruit
。我发现它不起作用(我知道为什么)但是也许无论如何我都可以实现writeFruits
。
我能以某种方式实施writeFruits
吗?
答案 0 :(得分:6)
在协变/逆变类型的实例中,您几乎需要在“基础”类型上定义类型类:
implicit object FruitWriter extends Writer[Fruit] {
def write(a : Fruit) = a match {
case _ : Apple => println("I am an apple!")
case _ : Orange => println("I am an orange")
}
}
您还可以使用方差来定义类型类,以便在需要Writer [Apple]时可以使用Writer [Fruit]。这很不幸,但是如果你想使用OO多态,你必须将其编码到功能方面。
* 强文 *另一种选择是使用HList进行写水果并自己完成所有的类型递归......
假设:
trait HList
object HNil extends HList
case class ::[A, Rest <: HList](head : A, tail : Rest)
然后我们可以做一些有趣的事情:
implicit def nilWriter = new Writer[HNil] = { def write(o : HNil) = () }
implicit def hlistWriter[A, Rest](implicit aw : Writer[A], rw : Writer[Rest]) =
new Writer[A :: Rest] {
def write(o : (A :: Rest)) = {
aw.write(o.head)
rw.write(o.tail)
}
}
现在
write( new Orange :: new Apple :: HNil)
注意:我没有测试过这段代码,但是递归跨越类型的概念是合理的。我实际上并没有推荐这种方法。
答案 1 :(得分:4)
您只需挑选Fruit
存在Writer
的{{1}}。不幸的是,一旦你转向Fruit
,你就失去了自动找出哪个是哪个的能力。如果你必须以这种方式设置问题 - 而不是汇编可写水果或某些东西的列表 - 那么一个合理的选择是再次使用FruitWriter
拆分类型:
def writeOne[T](t:T)(implicit w:Writer[T]){w.write(t)} // New name to avoid shadowing
implicit object FruitWriter extends Writer[Fruit] {
def write(f: Fruit) { f match {
case o: Orange => writeOne(o)
case a: Apple => writeOne(a)
}}
}
scala> val fruits = List(new Apple, new Orange)
fruits: List[Fruit] = List(Apple@1148ab5c, Orange@39ea2de1)
scala> for (fruit <- fruits) writeOne(fruit)
I am an apple!
I am an orange!
答案 2 :(得分:2)
或者也许案例类适合你?
abstract class Fruit {}
case object Orange extends Fruit
case object Apple extends Fruit
trait Writer[T] {def write (t:T)}
implicit object FruitWriter extends Writer [Fruit] {
def write (fruit: Fruit) = fruit match {
case Apple => println ("I am an apple!")
case Orange => println ("I am an orange!")
}
}
def writeFruits (fruits: List[Fruit]) {
for (fruit <- fruits) write(fruit)
}
val fl = List (Orange, Apple, Apple, Orange, Apple)
writeFruits (fl)
I am an orange!
I am an apple!
I am an apple!
I am an orange!
I am an apple!
答案 3 :(得分:1)
这不完全是你想要的,但是你可以自由地建立你的hiearchy:
sealed trait Fruit
case class Orange extends Fruit with OrangeWriter
case class Apple extends Fruit
case class Banana extends Fruit
trait Writer {
def write()
}
trait AppleWriter extends Writer {
self: Apple =>
def write() {println("I am an apple!")}
}
trait OrangeWriter extends Writer {
self: Orange =>
def write() {println("I am an orange!")}
}
def writeFruits(fruits:List[Fruit]) {
fruits.collect{case w:Writer => w}.foreach(_.write())
}
writeFruits(List(Apple(), Orange(),Banana(), new Apple with AppleWriter))
正如您所看到的,您可以Fruit
个Writer
附加Orange
(此处Apple
s),您可以“动态”附加作家(最后一个{ {1}}中的{1}}。