从必须实现类型类的方法返回值

Returning a value from a method which must implement a typeclass

我正在尝试使用一个方法 return 一个必须实现类型类的值,我认为它更普遍地向我强调了我如何不理解 Scala 的通用参数解析过程。我有这样的情况:

trait IsContainer[A, T] {
  def getOtherContainer[O](implicit tc2: IsUnit[O]): O
}

trait IsUnit[A] { }
implicit val anIntIsUnit = new IsUnit[Int] { }

implicit def aListIsContainer[T] = new IsContainer[List[T], T] {
  def getOtherContainer[Int] = 3
}

这引发了编译错误:Missing implementation for: def getOtherContainer。我对这里应该发生什么的不知情的猜测是 Scala 看到我已经传递了通用参数 O,并考虑如果 O 类型的所有实例都一致则实现的方法。所以在这种情况下(因为我已经明确地告诉它 O = Int,它会检查范围内是否存在 IsUnit[Int] 的实例,并且该方法的输出类型是输入 O。如果这是正确的(我不是说它是!)那么为什么它不起作用?

更一般地说,如果我跳过 [O] 通用参数并让它猜测 - 所以我只是用 getOtherContainer = 3 实现了该方法 - 我是否也应该期望它起作用?为了推断 O 应该是什么,它是否扫描该行并查看 O 是否已在提到的三个地方中的任何一个具体填写,并据此推断?

谢谢!

主要问题是这个定义:

def getOtherContainer[Int] = 3

在这个定义中,Int是一个类型参数,而不是类型Int。完全一样

def getOtherContainer[T] = 3

所以你没有“明确地告诉它 O = Int”,你只是使用 Int 作为类型参数的名称而不是 O。由于这与特征中所需的签名不匹配,因此没有有效的 getOtherContainer 实现,您会收到错误消息。

正确的是

implicit def aListIsContainer[T] = new IsContainer[List[T], T] {
  override def getOtherContainer[O](implicit tc2: IsUnit[O]): O = ???
}

你喜欢的类型class

trait IsContainer[A, T] {
  def getOtherContainer[O](implicit tc2: IsUnit[O]): O
}

意味着如果 AT 类型的元组有一个 class 类型的实例,那么您知道如何做 getOtherContainer 对于任何 类型 O 具有类型 class IsUnit.

的实例

当您试图在实例定义中删除 (implicit tc2: IsUnit[O])[O] 时,您实际上是在试图违反 class.[=28= 类型的契约]

如果你想在一个实例中特化O(例如O := Int)那么你应该将类型参数O移动到类型class级别

trait IsContainer[A, T, O] {
  def getOtherContainer(implicit tc2: IsUnit[O]): O
}

abstract class IsContainer[A, T, O](implicit tc2: IsUnit[O]) {
  def getOtherContainer: O
}

trait IsContainer[A, T] {
  type O
  def getOtherContainer(implicit tc2: IsUnit[O]): O
}

然后你可以定义一个实例

implicit def aListIsContainer[T] = new IsContainer[List[T], T, Int] {
  override def getOtherContainer(implicit tc2: IsUnit[Int]): Int = 3
}

implicit def aListIsContainer[T] = new IsContainer[List[T], T, Int] {
  override def getOtherContainer: Int = 3
}

implicit def aListIsContainer[T] = new IsContainer[List[T], T] {
  override type O = Int
  override def getOtherContainer(implicit tc2: IsUnit[O]): O = 3
}

相应地。