我有一个由多个子类扩展的特征
trait Sup
case class Sub[A, B](a: A, f: B => B)(implicit val ev: A =:= B) extends Sup
case class Sub2[A, B](a: A, f: B => Unit)(implicit val ev: A =:= B) extends Sup
Run Code Online (Sandbox Code Playgroud)
和两个功能:
def foo[A, B](a: A, f: B => B)(implicit ev: A =:= B) = f(a)
def bar[A, B](a: A, f: B => Unit)(implicit ev: A =:= B) = f(a)
Run Code Online (Sandbox Code Playgroud)
现在,我可以执行某种形式的动态调度和调用,foo如果对象是,Sub并且bar对象是Sub2。
def dispatch(obj: Sup) = {
obj match {
case Sub(a, f) => foo(a, f)
case Sub2(a, f) => bar(a, f) // type mismatch: found: Nothing => Unit. required: B => Unit
}
}
Run Code Online (Sandbox Code Playgroud)
我也尝试过明确地传递证据,但会导致相同的错误:
case o @ Sub2(a, f) => bar(a, f)(o.ev) // type mismatch
Run Code Online (Sandbox Code Playgroud)
可行f: B => B(我可以打电话foo),但是f: B => Unit不起作用(我不能打电话),这很奇怪bar。
您实际上可以使用类型变量模式使其工作:
def dispatch(obj: Sup) = {
obj match {
case obj: Sub[a, b] => foo(obj.a, obj.f)(obj.ev)
case obj: Sub2[a, b] => bar(obj.a, obj.f)(obj.ev)
}
}
Run Code Online (Sandbox Code Playgroud)
这部分是对评论的回答,因为它并不真正适合那里:
顺便说一句,还有一个微妙之处我不明白:为什么 B => B 中的单位逆变
编译器的逻辑是什么 Nothing => Unit inference Staff
您需要从函数方差开始。X => Y是 的子类型X1 => Y1当且仅当X是 的超类型X1并且Y是 的子类型Y1。我们说它在 中是逆变的X,在 中是协变的Y。
因此,如果你修复Y = Unit,剩下的只是 中的逆变X。Any => Unit是 的子类型String => Unit, 是 的子类型Nothing => Unit。事实上,Nothing => Unit是最一般的B => Unit,这就是为什么它会在这个Sub2案例中被推断出来。
并且 B => B 不是(因为它推断 Any => Any)?
的情况B => B有所不同:String => String既不是 的子类型,也不是 的超类型Any => Any,或者 的Nothing => Nothing。即,B => B是不变的。因此,没有原则上的理由来推断任何特定的,在这种情况下,编译器使用( )B的上限,并变为。BAnyB => BAny => Any