Scala:表达式的类型与正式参数类型不兼容
trait Ingredient{}
case class Papperoni() extends Ingredient{}
case class Mushroom() extends Ingredient{}
trait ToppingDef[T] {
}
object PepperoniDef extends Serializable with ToppingDef[Papperoni] {
}
object MushroomDef extends Serializable with ToppingDef[Mushroom] {
}
class Oven[T <: Ingredient](val topping:ToppingDef[T]) {
}
class Pizza {
def cook = {
val topping =
if(someCondition()) { PepperoniDef }
else { MushroomDef}
new Oven(topping) // <-- build error here
}
}
我正在使用Scala 2.11。这个例子有点人为,但我已经剥离了与问题无关的所有内容,以提供一个简明的例子。Scala:表达式的类型与正式参数类型不兼容
我得到的最后一行的错误是:
Error:(26, 5) no type parameters for constructor Oven: (topping: ToppingDef[T])Oven[T] exist so that it can be applied to arguments (Serializable with ToppingDef[_ >: Papperoni with Mushroom <: Product with Serializable with Ingredient])
--- because ---
argument expression's type is not compatible with formal parameter type;
found : Serializable with ToppingDef[_ >: Papperoni with Mushroom <: Product with Serializable with Ingredient]
required: ToppingDef[?T]
new Oven(topping)
但是改变的最后一行到此例如:
new Oven(PepperoniDef)
建立罚款。所以当参数像这样显式传递时,编译器在查找类型时没有问题。
此外,从PepperoniDef
和MushroomDef
去除Serializable
特点是这样的:
object PepperoniDef extends ToppingDef[Papperoni] {
}
object MushroomDef extends ToppingDef[Mushroom] {
}
还建立。但在我的情况下,我需要Serializable。
我想我可以重新调整代码来解决这个问题(如果有必要),但我想知道发生了什么,我不知道为什么类型在第一种情况下是模棱两可的,或者为什么存在Serializable特质有什么作用。预先感谢任何见解。
编辑:谢谢你的回复,非常有帮助。我认为最简洁的解决方法是可以改变:
val topping =
这样:
val topping:ToppingDef[_ <: Ingredient] =
,其固化生成错误,并且不需要更改通用类,我想保持尽可能简单地进行无注释,以便让Scala尽可能多地推断出类型信息。
这并不回答为什么Serializable
的存在对此有任何影响的问题。
看来,帮助编译出与类型注释使这个编译:
val topping: ToppingDef[
_ >: Papperoni with Mushroom <: Ingredient with Product with Serializable] =
if (true) {
PepperoniDef
} else {
MushroomDef
}
我不认为这有与Serializable
类专门做,它似乎是一个编译器的怪癖我自无论如何,生产型都有混合型,包括Product with Serializable
。
您也可以通过制作T
协变来“放松”型签名,意味着Topping[Ingredient]
将被推断。这是因为在协ToppingDef[+T]
“是子类型”关系Papperoni <: Ingredient
指ToppingDef[Papperoni] <: ToppingDef[Ingredient]
,从而使共同的父T
:
trait ToppingDef[+T]
val topping: ToppingDef[Ingredient with Product with Serializable] =
if (true) {
PepperoniDef
} else {
MushroomDef
}
,这也编译没有类型注释。
编辑:
制作Oven
S型参数的存在,而不是普遍的量化类型似乎与Serializable
性状以及工作:
class Oven[_ <: Ingredient](val topping: ToppingDef[_])
val topping: Serializable with ToppingDef[_ <: Ingredient] =
if (true) {
PepperoniDef
} else {
MushroomDef
}
new Oven(topping)
你需要某种类型的信息添加到您的特点:
trait ToppingDef[+T <: Ingredient] {}
眼下topping
变量无法弄清楚,T
应该是一个Ingredient
,所以你需要告诉它。
一个解决办法 - 但它实际上没有必要,它并没有解释为什么从对象中删除'extends Serializable'还要编译... –
谢谢。你可以评论为什么[+ T
'+'表示协变性,你可以在文档中阅读更多关于它的信息,他们有一些例子:http://docs.scala-lang.org/tour/variances.html – Tyler
真正的问题是 - 为什么推断类型(可以简化为'使用ToppingDef [_
@TzachZohar阅读规范。 –
@TzachZohar没有规范,我看着'-Ytyper-debug'输出,但没有提供任何信息。闻起来像一个错误。 –