首页 > 解决方案 > Cats 使用 Seq 自动派生

问题描述

我想为某些类型定义相等性,这些类型可以是使用猫/小猫的其他对象或集合的一部分。我不想为每个其他类定义相等性。例如:

import cats.Eq

case class Foo(a: Int, bar: Bar)

case class Bar(b: Int)

object BarEq {
  implicit val barEq: Eq[Bar] = Eq.instance[Bar] {
    (b1, b2) => b1.b +1 == b2.b
  }
}

然后一个测试定义为

import cats.derived.auto.eq._


class BarEqTest extends FlatSpec with cats.tests.StrictCatsEquality {
  import BarEq._

  "bareq" should {
    "work" in {
      Foo(1, Bar(1)) should ===(Foo(1, Bar(2)))
      Bar(1) should ===(Bar(2))
      Some(Foo(1, Bar(1))) should ===(Some(Foo(1, Bar(2))))
    }
  }
}

这工作正常,但如果我尝试添加以下测试用例

Seq(Foo(1, Bar(1))) should ===(Seq(Foo(1, Bar(2))))

我明白了

[Error] types Seq[Foo] and Seq[Foo] do not adhere to the type constraint selected for the === and !== operators; the missing implicit parameter is of type org.scalactic.CanEqual[Seq[Foo],Seq[Foo]]
one error found

自动派生的 eq 如何与Option但不一起工作Seq,我怎样才能使它工作?我试图添加import cats.instances.seq._,但这也不起作用。

标签: scalatypeclassimplicitscala-catsgeneric-derivation

解决方案


EqCats 定义了for的实例,而scala.collection.immutable.Seq不是泛型scala.collection.Seq(或者此外scala.collection.mutable.Seq

import scala.collection.immutable.{BitSet, Queue, Seq, SortedMap, SortedSet}

private[kernel] trait EqInstances0 {
  implicit def catsKernelEqForSeq[A: Eq]: Eq[Seq[A]] = cats.kernel.instances.seq.catsKernelStdEqForSeq[A]
}

https://github.com/typelevel/cats/blob/main/kernel/src/main/scala/cats/kernel/Eq.scala#L283-L285

从 Scala 2.13.0 开始scala.Seqscala.collection.immutable.Seq. 但在 Scala 2.12.xscala.Seq中是scala.collection.Seq.

https://github.com/scala/scala/releases/tag/v2.13.0

所以在 Scala 2.12 中导入正确的集合类型

import scala.collection.immutable.Seq
Seq(Foo(1, Bar(1))) === Seq(Foo(1, Bar(2))) // true

Eq或为必要的集合定义您自己的实例

import cats.kernel.instances.StaticMethods

implicit def genericSeqEq[A: Eq]: Eq[collection.Seq[A]] = new Eq[collection.Seq[A]] {
  override def eqv(xs: collection.Seq[A], ys: collection.Seq[A]): Boolean =
    if (xs eq ys) true
    else StaticMethods.iteratorEq(xs.iterator, ys.iterator)
}

Seq(Foo(1, Bar(1))) === Seq(Foo(1, Bar(2))) // true

推荐阅读