我的特征可以被多个子类扩展
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
和两个功能:
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)
现在,我可以执行某种形式的动态调度,如果对象是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
}
}
我也尝试过明确地传递证据,但是会导致相同的错误:
case o @ Sub2(a, f) => bar(a, f)(o.ev) // type mismatch
f: B => B
有效(我可以叫foo
),但是f: B => Unit
不起作用(我不能叫bar
)很奇怪。
答案 0 :(得分:3)
没有回答,但要考虑一下:
case class Sub1[A, B](a: A, f: B => B)
case class Sub2[A, B](a: A, f: B => Unit)
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)
def dispatch(obj: Any) = obj match {
case Sub1(a, f) => foo(a, f)
case Sub2(a, f) => bar(a, f) // type mismatch: found: Nothing => Unit. required: B => Unit
}
此代码与您的代码有相同的问题,但是Sub1
和Sub2
案例类甚至没有implicit
块。
据我了解,万一类的implicit
部分不会影响模式解析。本节仅是在apply(a: A, f: B => B)(implicit val ev: A =:= B)
的伴随对象上调用Sub1/2
方法的语法糖。模式匹配使用unapply
方法在运行时匹配模式,而这个unapply
甚至不知道证据。
但是我仍然想知道为什么在没有此证据的情况下首先编译case
。
编辑::添加来自@AlexeyRomanov的有用评论
类型推断比类型擦除要多。但是,是的,编译器推断a的类型为Any和f的Any => Any,然后生成并使用证据表明Any =:= Any。在第二种情况下,它为f推断Nothing => Unit,因为B => Unit在B中是反变量的,并且找不到Any =:= Nothing。
答案 1 :(得分:2)
您实际上可以使用type variable patterns使其起作用:
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)
}
}
这部分是对评论的答案,因为它实际上并不适合其中:
顺便说一句,我仍然没有得到一个微妙之处:为什么B => B中的单位不变
此Nothing =>单元推理人员的编译器逻辑是什么
您需要从function variance开始。当且仅当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
,在这种情况下,编译器使用B
(Any
)的上限,并且B => B
变成{{1 }}。