Типы Скала и F ограниченные типы - PullRequest
0 голосов
/ 21 ноября 2018

Я изучаю F-связанные типы в Scala, и я столкнулся с ситуацией, когда я не знаю, в чем дело.

Я сделал три теста, код выглядит следующим образом:

import scala.collection.mutable

def test1() = {

  trait Abstract {
    type ThisType <: Abstract
    def deepCopy(): ThisType
  }

  case class Concrete1(a: Int) extends Abstract {
    override type ThisType = Concrete1
    override def deepCopy(): ThisType = this.copy()

  }

  case class Concrete2(a: Int) extends Abstract {
    override type ThisType = Concrete2
    override def deepCopy(): ThisType = this.copy()

  }

  val set = new mutable.HashSet[Abstract]()

  set ++= List(Concrete1(1), Concrete2(2))

  val set2: mutable.Set[Abstract] = set.map(_.deepCopy())

}

def test2() = {

  trait Abstract {
    type ThisType
    def deepCopy(): ThisType
  }

  case class Concrete1(a: Int) extends Abstract {
    override type ThisType = Concrete1
    override def deepCopy(): ThisType = this.copy()

  }

  case class Concrete2(a: Int) extends Abstract {
    override type ThisType = Concrete2
    override def deepCopy(): ThisType = this.copy()

  }

  val set = new mutable.HashSet[Abstract]()

  set ++= List(Concrete1(1), Concrete2(2))

  val set2: mutable.Set[Abstract] = set.map(_.deepCopy())

}

def test3() = {


  trait Abstract[T <: Abstract[T]] {
    def deepCopy(): T
  }

  case class Concrete1(a: Int) extends Abstract[Concrete1] {
    override def deepCopy(): Concrete1 = this.copy()

  }

  case class Concrete2(a: Int) extends Abstract[Concrete2] {
    override def deepCopy(): Concrete2 = this.copy()

  }

  val set = new mutable.HashSet[Abstract[_]]()

  set ++= List(Concrete1(1), Concrete2(2))

  val set2: mutable.Set[Abstract[_]] = set.map(_.deepCopy())

}

test1 работает нормально.test2 и test3 выдают ошибку во время компиляции.

В test2 я пропускаю, что ThisType является подтипом Abstract.Я понимаю, что если я не установлю эту верхнюю границу, ThisType может быть чем угодно.Но если у меня есть Set из Abstract и я выполняю deepCopy() из его элементов, разве это не будет того же типа?Компилятор выдает эту ошибку:

Error:(53, 45) type mismatch;
 found   : scala.collection.mutable.HashSet[Abstract#ThisType]
 required: scala.collection.mutable.Set[Abstract]
  val set2: mutable.Set[Abstract] = set.map(_.deepCopy())
                                           ^

Я не понимаю, почему в этом случае (test2) Abstract#ThisType отличается от типа Abstract и в test1.Это как-то связано с типами, зависящими от пути?Если да, что это за объяснение?

В test3 Я пытаюсь сделать де то же, что и в test1, но с параметрами типа этот компилятор выдает ошибку в строке val set2: mutable.Set[Abstract[_]] = set.map(_.deepCopy()), говоря:

Error:(78, 48) type mismatch;
 found   : scala.collection.mutable.HashSet[Any]
 required: scala.collection.mutable.Set[Abstract[_]]
Note: Any >: Abstract[_], but trait Set is invariant in type A.
You may wish to investigate a wildcard type such as `_ >: Abstract[_]`. (SLS 3.2.10)
  val set2: mutable.Set[Abstract[_]] = set.map(_.deepCopy())
                                              ^
Error:(140, 45) type mismatch;
 found   : scala.collection.mutable.HashSet[Abstract#ThisType]
 required: scala.collection.mutable.Set[Abstract]
  val set2: mutable.Set[Abstract] = set.map(_.deepCopy())
                                           ^
Error:(166, 48) type mismatch;
 found   : scala.collection.mutable.HashSet[Any]
 required: scala.collection.mutable.Set[Abstract[_]]
Note: Any >: Abstract[_], but trait Set is invariant in type A.
You may wish to investigate a wildcard type such as `_ >: Abstract[_]`. (SLS 3.2.10)
  val set2: mutable.Set[Abstract[_]] = set.map(_.deepCopy())
                                              ^

Это связано с подстановочными знаками, но я не знаю, как объявлять такие типы без подстановочных знаков.

1 Ответ

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

вот версия, которая показывает некоторые части из моего объяснения https://scalafiddle.io/sf/Wnk3ekK/2

, поэтому проблема в 2 scalac не может доказать, что Abstract является распространенным супертипом для typemeber из-за отсутствующей границы.обратите внимание, что ThisType может быть, например, Int, который на самом деле не является подтипом Abstract и, следовательно, не может быть включен в Set[Abstract]

в 3 - это проблема того, что Abstract[_] является экзистенциальной иэто не совсем так, так что вы можете вставить общий супертип, как показано на рисунке.

...