在范围内显示时未找到隐式

Implicit not found while it's presented in the scope

考虑以下示例:

sealed trait ST

object ST{
  case class ST1() extends ST
  case class ST2() extends ST
}

trait TypeClass[A]{
  def doSome(a: A): Unit
}

case class Test[T](t: T)

implicit val tp: TypeClass[Test[_ <: ST]] = ???  //the implicit

def foo[A: TypeClass](a: A) = implicitly[TypeClass[A]].doSome(a)

val v: Test[_ <: ST] = ???

foo(v) //error: implicit not found

SCASTIE

可以看出,所需的隐式在范围内,但编译器无法识别。

为什么会发生这种情况,是否有调用 foo 的解决方法?

如果您将 foo(v) 更改为 foo(v)(tp),它会(稍微)更好地解释为什么它不想使用 tp。

简而言之,def foo[A : TypeClass] 需要类型 TypeClass[A] 的隐式。 当您执行 foo(v) 时,A 变为 Test[_ <: ST],这意味着“某些 特定 TestST 的未知子类型”。因此,foo 想要 that 特定类型的隐式。

但是 tp 不是 。它是“TypeClass for Test or any subclass of ST”(显然 _ 在这两种情况下的意思略有不同,因为 v 是具体实例,必须具有 特定 类型)。

长话短说,Test[_ <: ST] 不是 v 的实际类型,而是 超类型它的类型。所以,为了让它工作,你只需要使 TypeClass 逆变(TypeClass[-A]) - 这将使 foo 接受 tp 作为隐式,因为它的类型将成为它所期望的子类型。

在隐式解析期间不推断存在类型,因此 f(v) 失败,因为它正在寻找具有非推断类型的隐式值

TypeClass[Test[_]]]
                |
          existential not inferred

但是如果您显式提供类型变量实例 foo[Test[_ <: ST]](v) 那么隐式解析应该可以工作,因为我们已经过了推理阶段。

它在 Scala 3 中工作可能是因为它在内部 rewrites 存在类型到精炼类型。