F绑定的类型和方法,在自变量和返回站点具有类型参数

时间:2018-11-26 12:18:04

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

我有一个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中使用类型参数。

2 个答案:

答案 0 :(得分:5)

  

如果类型不完全相同,那么deepCopy2会如何编译?

那很简单。之所以有效,是因为不涉及多态性。静态已知ConcreteType2具有deepCopy()方法,该方法返回ConcreteType2。您甚至可以从整个层次结构中删除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

进行调用

答案 1 :(得分: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()