在下面的代码块(同时使用scala 2.11
和2.12
)中,该方法apply
不编译,而applyInlined
编译。
package blar
trait Bar[T]
class A
class B
class C
trait Exploder[T] {
// Removing explode and changing Foo so that
// flatMap takes no param means it will compile
def explode(product: C): Seq[T]
val bar: Bar[T]
}
case object Exploder1 extends Exploder[A] {
def explode(product: C): Seq[A] = ???
val bar: Bar[A] = ???
}
case object Exploder2 extends Exploder[B] {
def explode(product: C): Seq[B] = ???
val bar: Bar[B] = ???
}
object Thing {
def apply(): Unit = List(Exploder1, Exploder2).foreach {
case exploder: Exploder[_] =>
wrapped(exploder)
}
def applyInlined(): Unit = List(Exploder1, Exploder2).foreach {
case exploder: Exploder[_] =>
flatMap(exploder.explode)(exploder.bar)
}
def flatMap[U: Bar](explode: C => TraversableOnce[U]): Unit = ???
def wrapped[T](exploder: Exploder[T]): Unit =
flatMap(exploder.explode)(exploder.bar)
}
错误消息是
[error] .../src/main/scala/blar/Bar.scala:34:42: type mismatch;
[error] found : blar.Bar[_1]
[error] required: blar.Bar[Object]
[error] Note: _1 <: Object, but trait Bar is invariant in type T.
[error] You may wish to define T as +T instead. (SLS 4.5)
[error] flatMap(exploder.explode)(exploder.bar)
[error] ^
[error] one error found
[error] (Compile / compileIncremental) Compilation failed
[error] Total time: 4 s, completed 03-Jan-2019 13:43:45
- 我的主要问题是为什么?这是一个错误吗?
如您所见applyInlined
区别仅在于它内联了wrapped
方法的主体。 这意味着以某种方式在方法中额外包装某些代码已经"欺骗"编译器工作。
另一个问题是,你能想到一个设计/黑客来避免这种事情而不会产生
Blar
协变吗? 如何编译内联版本?我可以用asInstanceOf
来做吗什么是 scala 推断类型是为了在没有显式类型参数的情况下调用
wrapped
?
-
我不知道。实验证据表明,它与
List
上显式[Exploder[_]]
类型注释的存在/不存在有关。如果没有List[Exploder[_]]
,则列表的推断类型变为List[Product with Serializable with Exploder[_ >: B with A <: Object]]
无论出于何种原因,它都会以某种方式搞砸后续的模式匹配。
B with A
下限对我来说看起来有点可疑,但我无法解释为什么它会干扰模式匹配。 -
不,幸运的是,不需要
asInstanecOf
。以下两种变体都可以正常工作:def applyInlined: Unit = List[Exploder[_]](Exploder1, Exploder2).foreach { case exploder: Exploder[t] => { flatMap(exploder.explode)(exploder.bar) } }
与单独声明的隐式变量相同(请注意,现在您有一些类型
t
可以引用):def applyInlined2: Unit = List[Exploder[_]](Exploder1, Exploder2).foreach { case exploder: Exploder[t] => { implicit val bar: Bar[t] = exploder.bar flatMap(exploder.explode) } }
有关
[t]
-part 的更多信息,请参阅模式中的类型参数推断。 -
我假设这是一些合成的假人类型
_1
.