【问题标题】:F-bounded types and methods with type parameters at argument and return sitesF 有界类型和在参数和返回位置具有类型参数的方法
【发布时间】:2019-04-28 02:09:40
【问题描述】:

我有一个 F 有界类型,我的目标是创建一个类型参数化的方法以便能够重用它。下面是示例代码:

trait FType {
  type ThisType <: FType

  def deepCopy(): ThisType

}

class ConcreteType extends FType {

  override type ThisType = ConcreteType

  override def deepCopy(): ConcreteType = this

}

class ConcreteType2 extends FType {

  override type ThisType = ConcreteType2

  override def deepCopy(): ConcreteType2 = this

}

object FType {

  def deepCopy[T <: FType](_type: T): T = {
    _type.deepCopy()
  }

/*  def deepCopy2(c: ConcreteType2): ConcreteType2 = {
    c.deepCopy()
  }*/

  def main(args: Array[String]): Unit = {
    //deepCopy2(new ConcreteType2)
  }

}

但是,代码无法编译。编译器抛出此错误:

Error:(29, 19) type mismatch;
 found   : _type.ThisType
 required: T
    _type.deepCopy()

我知道它与路径相关类型有关,因为 _type.ThisTypeT 不是同一类型。

但是,如果 F 有界类型与使用 F 有界类型的类型不完全相同,我该如何利用 F 有界类型呢?如果类型不完全一样,那deepCopy2是怎么编译的?

注意:我知道我可以通过对每个具体类型使用方法重载来避免在deepCopy 中使用类型参数。

【问题讨论】:

    标签: scala path-dependent-type f-bounded-polymorphism


    【解决方案1】:

    如果类型不完全一样,deepCopy2是怎么编译的?

    这很简单。它之所以有效,是因为不涉及多态性。静态已知ConcreteType2 具有返回ConcreteType2deepCopy() 方法。你甚至可以从整个层次结构中删除type ThisType,它仍然会以同样的方式工作。


    但是,如果 F 有界类型与使用 F 有界类型的类型不完全相同,我该如何利用 F 有界类型呢?

    你需要告诉编译器它是一样的,因为你没有指定足够的东西。让我们看一个有效且具有多态性的示例:

    def deepCopy[A <: FType { type ThisType = A }](_type: A): A = _type.deepCopy()
    //                      ^ --important bit-- ^
    

    这定义了一个适用于任何A 的方法,即FType,并且它的类型成员ThisType 设置为A,将它们捆绑在一起。这意味着它适用于您对ConcreteTypeConcreteType2 的定义。但是,对于没有正确定义的类,它不会编译,例如这个:

    class Bogus extends FType {
      override type ThisType = ConcreteType2
      override def deepCopy(): ConcreteType2 = new ConcreteType2
    }
    
    deepCopy(new Bogus)
    

    或者,让我们从稍微修改过的方法开始:

    def deepCopyPD[A <: FType](_type: A): _type.ThisType = _type.deepCopy()
                                       ^path-dependent^
    

    它对ThisType 没有任何限制,但实际上编译器能够在所有情况下推断出它的正确版本:

    val x: ConcreteType2 = deepCopyPD(new ConcreteType2)
    val y: ConcreteType2 = deepCopyPD(new Bogus) // yep, this invocation is possible with such signature
    

    但是,也可以使用类型相等证据作为隐式参数进一步添加约束:

    def deepCopyPD2[A <: FType](_type: A)(implicit ev: _type.ThisType =:= A): A = _type.deepCopy()
    

    这再次禁止使用Bogus 调用

    【讨论】:

      【解决方案2】:

      在 F 有界类型中,您通常将 ThisType 作为类型参数而不是类型成员:

      trait FType[ThisType <: FType] {
        def deepCopy(): ThisType    
      }
      
      class ConcreteType extends FType[ConcreteType] {
        override def deepCopy(): ConcreteType = this
      }
      
      // in object FType
      def deepCopy[T <: FType[T]](_type: T): T = {
        _type.deepCopy()
      }
      

      注意区别:在FType.deepCopy 中,编译器知道_type.deepCopy() 的返回类型是T

      可以对类型成员做同样的事情:

      def deepCopy[T <: FType { type ThisType <: T }](_type: T): T = 
        _type.deepCopy()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-20
        • 1970-01-01
        相关资源
        最近更新 更多