虽然在another question上开头,但我遇到了似乎相关的不同谜语。这是其中之一:
trait Sys[S <: Sys[S]] {
type Peer <: Sys[Peer]
}
trait Fenced {
type Peer <: Sys[Peer]
}
def makeFence[S <: Sys[S]] = new Fenced { type Peer = S#Peer }
错误如下:
error: overriding type Peer in trait Fenced with bounds >: Nothing <: Sys[this.Peer];
type Peer has incompatible type
def makeFence[S <: Sys[S]] = new Fenced { type Peer = S#Peer }
^
为什么呢? (还试图将自我类型_:S =>
添加到Sys
,无关紧要)
虽然Rex的答案可以构造Fenced
对象,但它并没有真正解决我在使用类型投影(S#Peer
)时表示类型字符丢失的问题。我想出了另一种造成更严格限制的情景;我认为这是核心问题:
trait Test[S <: Sys[S]] {
def make[T <: Sys[T]](): Unit
make[S#Peer]()
}
error: type arguments [S#Peer] do not conform to method make's type
parameter bounds [T <: Sys[T]]
make[S#Peer]()
^
答案 0 :(得分:3)
我仍然不完全确定你正在寻找什么约束,但这是一种可能性:
trait Sys[S <: Sys[S]] {
type Peer <: Sys[Peer]
}
trait Fenced {
type MySys <: Sys[MySys]
type Peer = MySys#Peer
}
def makeFence[S <: Sys[S]] = new Fenced{ type MySys = S }
这使您(并且需要!)访问Peer
和Fenced
内的原始外部类型。我不确定Fenced
是否可以这样做,或者它是否必须抽象出外部类型。
答案 1 :(得分:3)
你可以让Sys
的类型参数协变吗?例如,这会编译:
trait Sys[+S <: Sys[S]] { type Peer <: Sys[Peer] }
trait Fenced { type Peer <: Sys[Peer] }
def makeFence[S <: Sys[S]] = new Fenced { type Peer = S#Peer }
现在,如果我们有以下内容(仅在REPL复制粘贴方便的情况下包装在对象中):
object Example {
case class SysX(i: Int) extends Sys[SysX] { type Peer = SysY }
case class SysY(j: Int) extends Sys[SysY] { type Peer = SysX }
}
import Example._
它按照我的预期运作:
scala> val fenceX = makeFence[SysX]
fenceX: java.lang.Object with Fenced{type Peer = Example.SysX#Peer} = ...
scala> val y: fenceX.Peer = SysY(1)
y: fenceX.Peer = SysY(1)
scala> val y: fenceX.Peer = SysX(1)
<console>:15: error: type mismatch;
found : Example.SysX
required: fenceX.Peer
val y: fenceX.Peer = SysX(1)
我认为哪个(我认为)是什么?