为何《Scala with Cats》中两种方差问题无法同时实现?我是否理解有误?
《Scala with Cats》方差问题澄清
你的测试代码能正常运行,是因为它刚好避开了书中提到的“两种方差需求无法同时满足”的冲突场景,下面具体解释:
你的代码为什么没问题
你的Printer是逆变类型(-T),逆变的核心规则是:若B <: A,则Printer[A] <: Printer[B]。这带来两个关键特性:
- 当调用
PrinterUse.print(B)时,Scala的隐式解析会优先选择最具体的Printer[B.type]实例(也就是你定义的bPrinter),所以输出b printer print B。 - 当调用
PrinterUse.print(C)时,因为没有定义cPrinter,隐式解析会向上查找兼容的实例。根据逆变规则,Printer[A]是Printer[C.type]的子类型,所以通用的aPrinter会被选中,自然能正常打印。
书中的“无法同时达成”指什么
书中的矛盾点出现在协变类型与逆变实例的交叉场景,比如结合协变集合List[+T]的情况:
假设我们希望:
- 复用通用实例:能用
Printer[List[A]]打印List[B](因为B <: A); - 保留具体实例:为
List[B]单独定义的Printer[List[B]]能被优先选中。
这时候就会出现冲突:
- 如果
Printer是逆变-T,那么Printer[List[A]]可以被用作Printer[List[B]](满足需求1),但协变的List[B] <: List[A]会让逆变的Printer[List[A]]成为Printer[List[B]]的候选,这会在某些场景下导致隐式解析歧义,或者无法同时兼顾“精准匹配子类型”和“复用父类型实例”的需求。 - 如果把
Printer改成协变+T,那么Printer[List[B]]不能被当作Printer[List[A]]使用(失去需求1的复用能力),但能精准匹配List[B]的实例。
简单说,书中的“无法同时达成”是指无法让一个类型既支持“父类型实例复用给子类型”(逆变的优势),又支持“子类型实例优先于父类型匹配”(精准匹配的需求),在涉及嵌套协变类型时这个矛盾会更突出。而你的代码没有涉及嵌套协变类型,只是单一层次的逆变隐式解析,所以没有触发这个冲突。
内容的提问来源于stack exchange,提问作者Kicey
相关产品推荐
相关产品推荐

