首页 > 解决方案 > 为什么 scala 在包装 EitherT 时不能推断出正确的类型?

问题描述

这是代码:

// eventually will be an implicit class with extension methods
class EitherTWrapper [L,R] (ei: EitherT[Future,L,R])

new EitherTWrapper(??? : EitherT[Future,Nothing,Boolean])

编译失败:

type mismatch;
 found   : cats.data.EitherT[scala.concurrent.Future,Nothing,Boolean]
 required: cats.data.EitherT[scala.concurrent.Future,L,Boolean]
Note: Nothing <: L, but class EitherT is invariant in type A.
You may wish to define A as +A instead. (SLS 4.5)

如果我明确地提供类型,它工作正常,如下所示:

new EitherTWrapper[Nothing,Boolean](??? : EitherT[Future,Nothing,Boolean])

这会起作用,但如果我试图使它成为一个隐式类,我就不能这样做。

我希望这行得通。如何定义一个可以包装 EitherT 的类?

标签: scalascala-cats

解决方案


正如错误所暗示的,将包装器更改为class EitherTWrapper [+L,R] (ei: EitherT[Future,L,R])将修复您的编译错误。

您的错误指出Nothing <: L, but class EitherT is invariant in type A.- 这意味着它Nothing是 的子类型L,因此声明L是非法的,因为这意味着您明确L不希望它的子类型(即L不变)。

声明某事物+L使其成为协变的,使您想要的成为可能。阅读更多关于 scala 文档中的方差:https ://docs.scala-lang.org/tour/variances.html

以下代码(来自文档)有效的原因是因为 ScalaList被定义为List[+A],这意味着您也可以传入List[Cat]和传递List[Dog]给一个接受 a 的函数List[Animal]

abstract class Animal {
  def name: String
}
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal

object CovarianceTest extends App {
  def printAnimalNames(animals: List[Animal]): Unit = {
    animals.foreach { animal =>
      println(animal.name)
    }
  }

  val cats: List[Cat] = List(Cat("Whiskers"), Cat("Tom"))
  val dogs: List[Dog] = List(Dog("Fido"), Dog("Rex"))

  printAnimalNames(cats)
  // Whiskers
  // Tom

  printAnimalNames(dogs)
  // Fido
  // Rex
}

在斯卡斯蒂


推荐阅读