为什么打包EitherT时scala不能推断正确的类型?

问题描述 投票:0回答:2

这里是代码:

// 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的类?

scala scala-cats
2个回答
0
投票

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

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

将某些内容声明为+L使其协变,从而使您想要的成为可能。在scala文档中详细了解方差:https://docs.scala-lang.org/tour/variances.html

下面的代码(来自docs)起作用的原因是因为Scala的List被定义为List[+A],这意味着您还可以将List[Cat]List[Dog]传递给采用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
}

On Scastie


0
投票

显然,这是一个已知的scala编译器错误(限制?):https://github.com/scala/bug/issues/9453

似乎有两种解决方法:

  • 使包装器上的类型为协变(不是很好,因为现在包装器与被包装的东西具有不同的方差行为,并且仅当类型参数没有被相反使用时才起作用)。
  • 通过创建单独的包装器,特别用EitherT处理Nothing的版本。即使试图将包装器用作隐式类,此方法也有效。
© www.soinside.com 2019 - 2024. All rights reserved.