为什么effects
不是Effect[A]
?类型应排在foo
。
/***
scalaVersion := "2.11.8"
*/
trait Effect[A]
sealed trait ActionResult[+M, +A] {
}
sealed trait ModelUpdated[+M] extends ActionResult[M, Nothing] {
}
sealed trait HasEffect[+M, +A] extends ActionResult[M, A] {
}
sealed trait UpdateSilent
object ActionResult {
case object NoChange extends ActionResult[Nothing, Nothing]
final case class ModelUpdate[M](newModel: M) extends ModelUpdated[M]
final case class ModelUpdateSilent[M](newModel: M) extends ModelUpdated[M] with UpdateSilent
final case class EffectOnly[A](effect: Effect[A]) extends ActionResult[Nothing, A] with HasEffect[Nothing, A]
final case class ModelUpdateEffect[M, A](newModel: M, effect: Effect[A]) extends ModelUpdated[M] with HasEffect[M, A]
final case class ModelUpdateSilentEffect[M, A](newModel: M, effect: Effect[A])
extends ModelUpdated[M] with HasEffect[M, A] with UpdateSilent
def apply[M, A](model: Option[M], effect: Option[Effect[A]]): ActionResult[M, A] = (model, effect) match {
case (Some(m), Some(e)) => ModelUpdateEffect(m, e)
case (Some(m), None) => ModelUpdate(m)
case (None, Some(e)) => EffectOnly(e)
case _ => NoChange
}
}
object Main {
def foo[A, B]: ActionResult[A, B] = ???
def dispatch[A, B] = {
foo[A, B] match {
case ActionResult.NoChange =>
false
case ActionResult.ModelUpdate(newModel) =>
false
case ActionResult.ModelUpdateSilent(newModel) =>
true
case ActionResult.EffectOnly(effects) =>
true
case ActionResult.ModelUpdateEffect(newModel, effects) =>
val e: Effect[A] = effects
false
case ActionResult.ModelUpdateSilentEffect(newModel, effects: Effect[A]) =>
true
}
}
}
答案 0 :(得分:1)
我不是每个人都有答案,但这里有一些想法。首先,我已经简化并澄清了您的代码示例,以尽量减少问题:
trait Effect[A]
trait ActionResult[+M, +A]
trait ModelUpdated[+M] extends ActionResult[M, Nothing]
trait HasEffect[+M, +A] extends ActionResult[M, A]
case class ModelUpdateEffect[M, A](newModel: M, effect: Effect[A]) extends ModelUpdated[M] with HasEffect[M, A]
object Main {
def foo[M, A]: ActionResult[M, A] = ???
def dispatch[M, A] = {
foo[M, A] match {
case ModelUpdateEffect(newModel, effect) =>
val e: Effect[A] = effect // does not compile
false
case _ => true
}
}
}
让我们注意我们为该行获取的错误消息:
type mismatch;
found : Effect[Any]
required: Effect[A]
Note: Any >: A, but trait Effect is invariant in type A.
编译器决定effect
的类型为Effect[Any]
,这有点奇怪。但是,让我们看看如果我们取代这个定义会发生什么:
case class ModelUpdateEffect[M, A](newModel: M, effect: Effect[A]) extends ModelUpdated[M] with HasEffect[M, A]
用这个:
case class ModelUpdateEffect[M, A](newModel: M, effect: Effect[A]) extends HasEffect[M, A]
现在我们收到一条不同的错误消息:
type mismatch;
found : Effect[?A1] where type ?A1 <: A (this is a GADT skolem)
required: Effect[A]
Note: ?A1 <: A, but trait Effect is invariant in type A.
在这种情况下,类型真的不匹配。让我们来看看吧。我们从case
声明外部知道我们有ActionResult[M, A]
。但由于类型参数A
的协方差,ActionResult[M, A]
可能是ActionResult[M, B] forSome { type B <: A }
。换句话说,某些类型B
可能是A
的子类型,而foo[M, A]
可能会返回ActionResult[M, B]
。在这种情况下,effect
将是Effect[B]
,并且由于Effect
的类型参数是不变的,因此此类型与Effect[A]
不兼容。