我正在学习Scala中的F绑定类型,遇到一种我不知道怎么回事的情况。
我做了三个测试,代码如下:
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())
^
这与通配符有关,但是我不知道如何在没有通配符的情况下声明此类。
答案 0 :(得分:1)
这里有一个版本,显示了我的解释https://scalafiddle.io/sf/Wnk3ekK/2
中的某些部分因此2 scalac中的问题不能证明Abstract
由于缺少边界而成为类型成员的常见超类型。看到ThisType
可以例如是Int
,它实际上不是Abstract
的子类型,因此没有资格加入Set[Abstract]
问题是Abstract[_]
是存在的,并且不能像那样工作,因此您可以插入所示的公共超类型。