Я изучаю 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())
^
Это связано с подстановочными знаками, но я не знаю, как объявлять такие типы без подстановочных знаков.