根据类型类设置抽象类型

Setting abstract type based on typeclass

我有这样一个例子:

abstract class IsBaseTC[A] { type Self }
abstract class JustHoldsTypeMember[A] extends IsBaseTC[A] 
implicit val doubleHoldsTypeMember = new JustHoldsTypeMember[Double] { type Self = Double }

abstract class IsActualTC[A, T](implicit val aIsBaseTc: IsBaseTC[T]) extends IsBaseTC {
  type Self = A
  def get(self: A): aIsBaseTc.Self
}

case class Container[T](
  get: T
)

implicit val containerOfDoubleIsActual = new IsActualTC[Container[Double], Double] {
  def get(self: Self) = self.get // type mismatch; 
                                  // found self.get.type (with underlying type Double) 
                                  // required this.aIsBaseTc.self
}

这给了我上面显示的错误。除非我没能正确地遵循我自己的逻辑,否则 this.aIsBaseTc.self 应该解析为 Double。有没有办法让编译器相信是这种情况?

感谢您的帮助。

确实都是双打,但这就是价值。不是同一类型。

def get(self: A)请求的类型是aIsBaseTc.Self,你的情况是doubleHoldsTypeMember.Self

当尝试访问 doubleHoldsTypeMember 的自我时,您会得到:

问题是,您无法创建 this.aIsBaseTc.Self,因为它不可访问。

为了解决它,您可以尝试创建一个 Self 的实例,您可以在其中访问它:

abstract class IsBaseTC[A] { type Self; def createSelf(): Self }
abstract class JustHoldsTypeMember[A] extends IsBaseTC[A]
implicit val doubleHoldsTypeMember: JustHoldsTypeMember[Double] = new JustHoldsTypeMember[Double] {
  type Self = Double
  override def createSelf() = 3.14
}

并使用它:

implicit val containerOfDoubleIsActual: IsActualTC[Container[Double], Double] = new IsActualTC[Container[Double], Double] {
  override def get(self: Self) = this.aIsBaseTc.createSelf()
  override def createSelf() = ???
}

然后,当运行:

containerOfDoubleIsActual.get(Container(4.12))

它将打印:

3.14

创建于 doubleHoldsTypeMember

的 createSelf

事情在范围内。

更简单的例子是

trait A { type T }
implicit val a: A { type T = Int } = null
def test(implicit x: A): Unit = {
  implicitly[x.T =:= Int] // doesn't compile, cannot prove that x.T =:= Int
}

您假设 xaaIsBaseTc 在您的符号中是 doubleHoldsTypeMember)。但实际上x不是ax会在调用test时解析(在test调用点范围内)而是a在当前范围内定义(test 定义的范围)。同样,aIsBaseTc 不是 doubleHoldsTypeMember

(查看implicit x: Ximplicitly[X]的区别。)

至于任何匿名 class

implicit val containerOfDoubleIsActual = new IsActualTC[Container[Double], Double] {
  def get(self: Self) = self.get // type mismatch; 
}

是 shorthand 为

class IsActualTCImpl extends IsActualTC[Container[Double], Double] {
  def get(self: Self) = self.get // type mismatch; 
                                 // aIsBaseTc is not doubleHoldsTypeMember here
}
implicit val containerOfDoubleIsActual = 
  new IsActualTCImpl // implicit is resolved here
                     // aIsBaseTc becomes doubleHoldsTypeMember here

并且由于 aIsBaseTc 不是 doubleHoldsTypeMemberaIsBaseTc.Self 不是 Double

可能的解决方法是在 IsActualTC

中再添加一个类型参数 S
abstract class IsActualTC[A, T, S](implicit val aIsBaseTc: IsBaseTC[T] {type Self = S}) extends IsBaseTC {
  type Self = A
  def get(self: A): S
}

implicit val containerOfDoubleIsActual = new IsActualTC[Container[Double], Double, Double] {
  def get(self: Self) = self.get
}

或者对IsActualTC

的隐式参数添加类型细化
abstract class IsActualTC[A, T](implicit val aIsBaseTc: IsBaseTC[T] {type Self = T}) extends IsBaseTC {
  type Self = A
  def get(self: A): aIsBaseTc.Self
}

implicit val containerOfDoubleIsActual = new IsActualTC[Container[Double], Double] {
  def get(self: Self) = self.get
}