Scala类型系统,找不到内联的共同祖先

时间:2019-10-07 08:21:37

标签: scala scala-cats mockito-scala

我正在使用一些声明为def execute]C <: A#C](cmd: C):EitherT[Future, Fail, Seq[A#E]](其中A是该类的泛型类型)的泛型方法的重类型系统上。

这很好。但是,在测试中,当我模拟那些调用时,我必须明确键入FailA#E的超类型,否则我的代码无法编译。

// Event is the base type of Receiver#E
val event:Event = SubOfEvent()
handler.execute(any[SubOfCommand]) returns Seq(event).asRightT[Future, Fail]

val fail:Fail = SubOfFail()
handler.execute(any[SubOfCommand]) returns fail.asLeftT[Future, Seq[Receiver#E]]

如果我内联eventfail的声明,则会出现类型不匹配

  found   : cats.data.EitherT[scala.concurrent.Future,SubOfFail,scala.collection.immutable.Seq[SubOfEvent]]
  required: cats.data.EitherT[scala.concurrent.Future,Fail,scala.collection.immutable.Seq[Receiver#E]]
     (which expands to)  cats.data.EitherT[scala.concurrent.Future,Fail,scala.collection.immutable.Seq[Event]]
 Note: SubOfFail <: Fail, but class EitherT is invariant in type A.
 You may wish to define A as +A instead. (SLS 4.5)
     handler.execute(any[SubOfCommand]) returns SubOfFail().asLeftT[Future,
                                                                   ^

我了解到有关EitherT类型为A不变的消息。但是我希望它能够将EitherT[F, SubOfA, B]转换为EitherT[F, SubOfA.asInstanceOf[A], B]

有人可以帮助我揭示我推理中的缺陷吗?

谢谢

1 个答案:

答案 0 :(得分:1)

  

但是我希望它能够将EitherT[F, SubOfA, B]转换为EitherT[F, SubOfA.asInstanceOf[A], B]

保持不变就意味着不可能以这种方式“翻译”:EitherT[F, SubOfA, B]根本不是EitherT[F, A, B]

现在,有一个单独的问题是为什么尽管整个fail的类型都是预期的,但Fail的类型却不能被推断为fail.asLeftT[Future, Seq[Receiver#E]]。答案是,Scala类型推断不能那样工作。键入expression.method(...)时,它将首先键入expression,并且不能使用method的预期返回类型。

您仍然可以内联编写它们,但是您需要输入文字说明:

(SubOfFail(): Fail).asLeftT[Future, Seq[Receiver#E]]

对于Seq,显式类型参数也将起作用:

Seq[Event](SubOfEvent()).asRightT[Future, Fail]