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。这个例子有点做作,但我已经删除了与问题无关的所有内容,以提供一个简洁的例子。
我在最后一行得到的错误是:
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)
建立良好。因此,当参数像这样明确地传递时,编译器找到类型没有问题。
另外,从Serializable
和PepperoniDef
移除MushroomDef
特征,如下所示:
object PepperoniDef extends ToppingDef[Papperoni] {
}
object MushroomDef extends ToppingDef[Mushroom] {
}
也建立。但是在我的情况下,我需要Serializable。
我认为我可以重新构建代码以便在必要时解决这个问题,但我想了解发生了什么,我不知道为什么类型在第一种情况下是模糊的,或者为什么存在Serializable特征有任何影响。提前感谢任何见解。
编辑:谢谢你的回复,非常有帮助。我认为最简洁的解决方法是改变这个:val topping =
到此:
val topping:ToppingDef[_ <: Ingredient] =
它修复了构建错误,并且不需要更改泛型类,我希望尽可能简单地保留这些类,以便让Scala尽可能多地推断类型信息。
这并没有回答为什么Serializable
的存在对此有任何影响的问题。
答案 0 :(得分:3)
似乎使用类型注释帮助编译器进行编译:
val topping: ToppingDef[
_ >: Papperoni with Mushroom <: Ingredient with Product with Serializable] =
if (true) {
PepperoniDef
} else {
MushroomDef
}
我不认为这与Serializable
类具体有关,它似乎是编译器的怪癖,因为生成的类型具有混合类型,包括Product with Serializable
。< / p>
你也可以'放松&#34;通过制作T
协变来表示类型签名,意味着Topping[Ingredient]
将被推断。这是因为&#34;是&#34;的子类型。协变Papperoni <: Ingredient
上的关系ToppingDef[+T]
表示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)
答案 1 :(得分:1)
您需要在特征中添加一些类型信息:
trait ToppingDef[+T <: Ingredient] {}
目前topping
变量无法确定T
应该是Ingredient
,因此您需要告诉它。