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

Scala 类型参数化或结构子类型化或,scala,Scala,你好! 我是scala的新手,因此在开发过程中提出了以下问题: 我想描述类树[T],其中T是类型参数。 但是T应该受到约束-它应该有两种方法: def key():A,其中A是某种类型,派生自方法的实现(!) 和def union(x:T):T,其中T与类型参数相同。 我想这个约束可以用几种方式表达: 定义两个特征,一个是使用方法键,另一个是使用方法联合(两个特征是由于这些方法的独立性) 使用结构子类型 还有别的 那么,我怎样才能做到这一点呢?还有其他方式吗 另外,如果可以很容易地为简单类型(如

你好! 我是scala的新手,因此在开发过程中提出了以下问题:

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

  • 定义两个特征,一个是使用方法,另一个是使用方法联合(两个特征是由于这些方法的独立性)
  • 使用结构子类型
  • 还有别的
  • 那么,我怎样才能做到这一点呢?还有其他方式吗


    另外,如果可以很容易地为简单类型(如String、Int等)添加这些方法,这也会很好。

    结构类型是用Java反射实现的,因此它们会降低性能。对于像脚本一样的短程序,或者对于初始化来说,这都是可以的,但是任何密集的使用都可能会使程序崩溃

    所以我会选择你的第一个选择。您至少需要两个类型参数。但如果您不需要更精细的粒度,您只能选择一个特性:

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

    如果您希望能够将这些方法“添加”到简单类型中,那么最好使用类型类,看看Kevin Wright的答案,它展示了如何“添加”一个
    zero
    和一个
    append
    方法到
    Int
    String
    您可以为
    键定义一个结构类型,但不能为
    联合定义结构类型。结构类型不能引用在其外部定义的抽象类型。所以这是行不通的:

    trait Tree[T <: { 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
    
    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"))
    }
    
    或者,您可以将其与类型类模式一起使用,只需做一些更改:

    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
    
    类型类模式使用上下文边界。更多信息,请查阅。如今,这种风格比前一种风格更受欢迎,因为它在许多方面都更灵活。尽管如此,两者都会起作用

    在这种情况下,可以这样使用:

    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
    
    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"))
    }
    
    隐式对象IntVal扩展了TreeVal[Int]{
    类型A=Int
    定义键(v:Int)=v
    def接头(x:Int,y:Int)=x+y
    }
    类树[T:TreeVal](节点:T,左:选项[Tree[T]],右:选项[Tree[T]]){
    val treeVal=隐式[treeVal[T]]
    进口特雷瓦尔_
    override def toString=“(%s<%s>%s)”格式(左.getOrElse(“o”)、键(节点)、右.getOrElse(“o”))
    }
    
    听起来他希望在
    T
    上定义方法,而不是在
    树上定义方法。但还有一个问题:我为什么要在
    隐式对象IntVal
    中显式指定
    类型A
    ?它可以从定义中推断出来吗?也许你可以使用参数化版本的方法
    key
    def key[A]:A
    @incrop,我试过了,但是我仍然需要显式地写类型名,比如
    覆盖def key[String]=…
    ,因为在其他情况下会出现两个不同的
    key
    方法(一个摘要,没有定义),我不明白,为什么A型不是inferred@newf嗯,
    key
    必须有一个返回类型。因为它的定义是抽象的,Scala可以推断出它是什么类型。而且因为你只是说“a是某种类型”,我做得再好不过了。@newf顺便说一句,
    def key[String]
    并不意味着
    key
    的类型参数将是
    String
    ——您不能将参数化方法重写为非参数化。该def的作用与
    def key[T]相同
    ,但是调用参数
    String
    而不是
    T
    --
    String
    将是参数,而不是类
    字符串