类型参数化或结构子类型或

美好的一天!我对scala很新,所以在开发期间提出了以下问题:

我想描述 class Tree[T] ,其中 T 是类型参数 . 但是T应该被约束 - 它应该有2个方法: def key(): A ,其中 A 是某种类型,派生自方法的实现(!)和 def union(x: T): T ,其中 T 与类型参数相同 . 我想这个约束可以用几种方式表达:

  • 用方法 key 定义两个特征,用方法 union 定义两个特征(两个特征是因为这些方法的独立性)

  • 使用结构子类型

  • 别的......

那么我怎么能以各种方式做到这一点?并存在其他方式吗?

如果为简单类型(如String,Int等)添加这些方法也很容易 .

回答(3)

3 years ago

您可以为 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"))
}

3 years ago

如果您希望能够将这些方法“添加”到简单类型,那么您最好使用类型类 . Read more about type classes in this question,看看Kevin Wright的答案,其中显示了如何将 zeroappend 方法“添加”到 IntString .

3 years ago

结构类型使用Java反射实现,因此它们会降低性能 . 它适用于类似脚本的短程序或初始化,但任何密集的使用都可能让你的程序瘫痪......

所以我会先选择你 . 您至少需要两个类型参数 . 但是,如果您不需要更精细的粒度,则只能使用一个特征:

trait Tree[T,A] {
    def key(): A
    def union( x: T ): T
}