我正在使用此处定义的树...
https://gist.github.com/schmmd/1271891
其中...
class Tree[+T]
case object Empty extends Tree[Nothing]
case class Node[T](val elem: T, val left: Tree[T], val right: Tree[T]) extends Tree[T]
我添加了这个特性...
trait sum[T] {
def +(value: T): T
}
我定义了这棵树......
val a = Node(1, Node(1, Empty, Node(5, Empty, Empty)), Node(2, Node(3, Empty, Empty), Empty))
然后我写了这个函数来总结元素......
def sumTree[T <: sum[T]](t: Tree[T]): T = t match {
case Empty => 0
case Node(e, left, right) => e + sumTree(left) + sumTree(right)
}
问题
1)为什么我必须定义一个特征(假设我已正确定义)使用“+”?没有它,编译器会将其视为尝试连接字符串。
2)我不知道如何处理“空”。我希望在模式匹配时将“Empty”视为0,但由于通用处理,我不能。是不是我不能用泛型做这个工作?我必须事先指定它接受/返回的类型吗?
答案 0 :(得分:2)
因为元素类型removeAnnotation()
是通用的,所以需要提供一个辅助结构来处理添加。 Scala不知道如何在没有进一步信息的情况下添加T
类型的两个元素。这就是您定义特征T
的原因。正如您所怀疑的那样,您还需要一种方法来了解零元素是什么。所以你宁愿使用这样的东西:
sum
请注意,我们使用两个操作数定义trait Sum[T] {
def zero: T
def plus(x: T, y: T): T
}
。然后,不要求plus
是T <: Sum[T]
的子类型,而是提供隐式值(称为类型类)。这使得使用任意类型的树更容易,即使元素没有实现Sum
。
现有的类型类可以实现这个功能,基本上是一个&#34; monoid&#34;。 Scala标准类库具有您可以使用的Numeric
。它不仅仅是一个幺半群,定义了几个算术运算,包括Sum
和zero
。
然后你的聚合函数变为:
plus
您还可以导入一些语法助手:
def sumTree[T](t: Tree[T])(implicit num: Numeric[T]): T = t match {
case Empty => num.zero
case Node(e, left, right) =>
num.plus(e, num.plus(sumTree(left), sumTree(right)))
}
另见: