F-ограниченные типы и методы с параметрами типов на сайтах аргументов и возврата - PullRequest
0 голосов
/ 26 ноября 2018

У меня есть 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.ThisType отличается от типа T.

Но кактогда, могу ли я воспользоваться F-ограниченными типами, если F-ограниченный тип не совсем совпадает с типом, использующим F-ограниченный тип?Если типы не совпадают, как это компилируется deepCopy2?

Примечание : я знаю, что могу избежать использования параметров типа в deepCopy, используя перегрузку методов для каждого изконкретные виды.

Ответы [ 2 ]

0 голосов
/ 26 ноября 2018

Если типы не совсем одинаковые, как работает этот 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, связывая их вместе.Это означает, что это будет работать для ваших определений ConcreteType и ConcreteType2.Однако он НЕ будет компилироваться для классов, которые не определены должным образом, таких как этот:

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

0 голосов
/ 26 ноября 2018

В 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()
...