8

在思考另一个问题时,我遇到了似乎相关的不同谜语。这是其中之一:

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 }
                                                      ^

为什么?(也尝试将 self-type 添加_: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]()
                  ^
4

2 回答 2

3

你能让Sys's 的类型参数协变吗?例如,这编译:

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)

哪个(我认为)是你想要的?

于 2012-09-25T21:35:10.760 回答
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可以这样做,或者它是否必须跨外部类型进行抽象。

于 2012-09-25T21:32:05.730 回答