美好的一天! 我对scala很新,所以在开发期间提出了以下问题:
我想描述类Tree [T] ,其中 T 是类型参数。 但是T应该受到约束 - 它应该有两种方法: def key():A ,其中 A 是某种类型,派生自方法的实现(!) 和 def union(x:T):T ,其中 T 与类型参数相同。 我想这种约束可以用几种方式表达:
那么我怎么能以各种方式做到这一点?还有其他方法存在吗?
如果为简单类型(如String,Int等)添加这些方法很容易也会很好。
答案 0 :(得分:5)
您可以为key
定义结构类型,但不能为union
定义结构类型。结构类型可能不是指在其自身之外定义的抽象类型。所以这不起作用:
trait Tree[T <: { def union(x: T): T }]
您可以定义Tree
的元素必须可用的特征:
trait TreeVal[T] {
type A
def key: A
def union(x: T): T
}
这可以用两种方式。首先,类必须实现该接口,这严重限制了哪些类可以用作键。这将是这样的:
trait Tree[T <: TreeVal[T]]
它也可以作为隐式转换提供,如下所示:
class IntVal(v: Int) extends TreeVal[Int] {
type A = Int
def key: A = v
def union(x: Int): Int = x + v
}
implicit def IntIsVal(v: Int): IntVal = new IntVal(v)
class Tree[T <% TreeVal[T]] // must be class, so it can receive parameters
这使用了所谓的视图绑定。查看更多信息,但足以说明您将能够处理任何已定义隐式转换且范围内的内容,就好像它是TreeVal
一样。例如:
class Tree[T <% TreeVal[T]](node: T, left: Option[Tree[T]], right: Option[Tree[T]]) {
override def toString = "(%s < %s > %s)" format (left.getOrElse("o"), node.key, right.getOrElse("o"))
}
或者,您可以将它与类型类模式一起使用,只需进行一些更改:
trait TreeVal[T] {
type A
def key(v: T): A
def union(x: T, y: T): T
}
class Tree[T : TreeVal] // must be class, so it can receive parameters
类型类模式使用上下文边界。查看更多信息。这种风格通常比现在的风格更受欢迎,因为它在许多方面更加灵活。不过,两者都有效。
在这种情况下,人们会像这样使用它:
implicit object IntVal extends TreeVal[Int] {
type A = Int
def key(v: Int) = v
def union(x: Int, y: Int) = x + y
}
class Tree[T: TreeVal](node: T, left: Option[Tree[T]], right: Option[Tree[T]]) {
val treeVal = implicitly[TreeVal[T]]
import treeVal._
override def toString = "(%s < %s > %s)" format (left.getOrElse("o"), key(node), right.getOrElse("o"))
}
答案 1 :(得分:3)
如果您希望能够将这些方法“添加”到简单类型,那么您最好使用类型类。 Read more about type classes in this question,查看Kevin Wright的回答,其中显示了如何向zero
和append
添加Int
和String
方法。
答案 2 :(得分:2)
结构类型是使用Java反射实现的,因此它们会降低性能。对于类似脚本的短程序或初始化来说没问题,但任何密集的使用都可能让你的程序瘫痪......
所以我会先选择你。您至少需要两个类型参数。但是,如果您不需要更精细的粒度,则只能使用一个特征:
trait Tree[T,A] {
def key(): A
def union( x: T ): T
}