Cats自动派生Eq对Option生效但Seq不生效的原因及解决方法
问题原因
cats.derived.auto.eq._提供的自动相等性派生仅针对样例类、密封特质这类代数数据类型(ADT)生效:- Option是Scala标准库定义的密封特质,属于标准ADT,只要内部元素类型存在Eq实例,auto.eq就可以自动推导生成对应Option类型的Eq实例,因此你的Option相关测试用例可以正常运行。
- Seq是通用集合特质,不属于ADT范畴,kitten的自动派生逻辑不会为这类泛型集合生成通用Eq实例。
- 你导入的
cats.instances.seq._确实提供了Seq类型的Eq实例,但该实例的生成存在前提:需要作用域内存在对应元素类型的Eq实例(这里是Eq[Foo])才能生成Eq[Seq[Foo]],而auto.eq自动派生的Eq[Foo]隐式优先级低于cats自带的集合实例优先级,编译器推导Eq[Seq[Foo]]时无法匹配到可用的Eq[Foo],最终导致StrictCatsEquality无法生成对应的CanEqual实例,抛出编译错误。
解决方案
你可以根据实际场景选择以下任意一种方案解决问题:
方案1:显式声明元素类型的Eq实例(保留Seq用法)
在测试代码的导入部分补充如下内容即可:
import cats.instances.int._ import cats.instances.seq._ // 显式派生Foo的Eq实例,提升隐式优先级,让cats的Seq实例可以识别 implicit val fooEq: Eq[Foo] = cats.derived.semiauto.eq.deriveEq[Foo]
修改后你的Seq测试用例可以正常编译运行。
方案2:用ADT类型的集合替代Seq
List是Scala标准库的ADT集合类型,auto.eq可以自动推导Eq[List[Foo]],不需要额外导入集合相关实例,直接修改测试用例即可:
List(Foo(1, Bar(1))) should ===(List(Foo(1, Bar(2))))
内容的提问来源于stack exchange,提问作者worldwideop
相关产品推荐
相关产品推荐

