0

我有一个 F-Bound 类型:

sealed trait A[AA <: A[AA]] {
  self: AA =>
}

还有第二种 F-Bound 类型,由第一种类型参数化。

sealed trait B[BB <: B[BB, AA], AA <: A[AA]] {
  self: BB =>
  val content: AA
}

我可以愉快地编写使用这些类型的案例类:

case class BInst[BB <: BInst[BB, AA], AA <: A[AA]](content: AA) 
     extends B[BInst[BB, AA], AA]

现在我想为案例类创建一个伴生对象,我可以通过特征 B 引用它,例如:

sealed trait A[AA <: A[AA]] { self: AA => }

sealed trait B[BB <: B[BB, AA], AA <: A[AA]] {
  self: BB =>
  val content: AA
  def companion: Companion[BB]
}

case class BInst[BB <: BInst[BB, AA], AA <: A[AA]](content: AA) 
     extends B[BInst[BB, AA], AA] {
  def companion: Companion[BInst[BB, AA]] = BInst
}

sealed trait Companion[+BB <: B[_, _]]
object BInst extends Companion[BInst]

但这无法编译,因为伴随参数化(最后一行)中的 BInst 需要类型参数。相似地

sealed trait Companion[BB[X, Y] <: B[X, Y]]

失败。伴生对象的正确类型是什么?

4

2 回答 2

1

我看到的唯一方法是放弃Companion/的泛型参数,BInst因为即使从类型角度来看也可能只有一个对象实例(只有一种BInst.type类型):

scala> sealed trait A[AA <: A[AA]] { self: AA => }

sealed trait B[BB <: B[BB, AA], AA <: A[AA]] {
  self: BB =>
  val content: AA
  def companion: Companion[_]
}

case class BInst[BB <: BInst[BB, AA], AA <: A[AA]](content: AA)
     extends B[BInst[BB, AA], AA] {
  def companion = BInst
}

sealed trait Companion[+BB <: B[_, _]]
object BInst extends Companion[BInst[_, _]]

defined trait A
defined trait B
defined class BInst
defined trait Companion
defined module BInst

之后,您实际上可以转换您的BInst(内部案例类):

def companion: Companion[BInst[BB, AA]] = 
    BInst.asInstanceOf[Companion[BInst[BB, AA]]

如果您不在Companion-trait/ -object 中强制转换类型BInst(最好只使用BB/ AA-independentBInst类的方法),则不会有获得 ClassCastException 的风险,.asInstanceOf[Companion[BInst[BB, AA]]]只会为您创建(克隆)新类型,BInst用作原型。

于 2015-04-15T13:59:05.773 回答
1

我试图将您在这里写的内容与您的其他问题合并: scala: Reference Trait with F-Bound Parameters

通过保持可编译性,这与我可以得到的代码一样接近:

import scala.language.higherKinds

trait A[AA <: A[AA]] { self: AA => }

trait B[
  X <: A[X], 
  This[Y <: A[Y]] <: B[Y, This]
] {
  self: This[X] =>
  def content: X 
  def companion: Companion[This]
}

trait Companion[Coll[X <: A[X]] <: B[X, Coll]]

case class BInst[X <: A[X]](content: X) 
extends B[X, BInst] {
  def companion: Companion[BInst] = BInst
}

object BInst extends Companion[BInst]

BB的 s 已替换为This, 参数的顺序已被交换,因此它与标准集合库中所做的更相似。

一般性评论。
你似乎不太确定你想从你的BInstBComp/中得到什么Companion。您的问题的两个版本,它们似乎具有完全不同的类型。如果您不太确定自己想要什么,建议尽可能简单。有轶事证据表明,所有这些 F-Bound-GenericCompanionCanBuildFromFactories 都很难正确处理

于 2015-04-22T14:50:33.013 回答