我有以下简单的代码:
trait MyBox[T] {
def capacity: Double
}
case class FruitBox[T](fruit: Int) extends MyBox[T] {
override def capacity = 1.0
}
object FruitBox {
def apply[T](fruit: Int): FruitBox[T] = new FruitBox[T](fruit)
}
以下代码也有效,我省略了类型参数T
case class FruitBox[T](fruit: Int) extends MyBox { //T is omitted for MyBox[T]
override def capacity = 1.0
}
object FruitBox{
def apply[T](fruit: Int): FruitBox[T] = new FruitBox(fruit) //T is omitted for new FruitBox
}
我会问为什么我可以省略类型参数?这背后的原因是什么?在我看来,在scala中,参数化类型必须具有类型参数才能成为具体类型。
答案 0 :(得分:1)
为了防止可能的误解,这里不编译:
trait MyBox[T] {
def capacity: Double
}
case class FruitBox[T](fruit: Int) extends MyBox {
override def capacity = 1.0
}
你不能在这里省略[T]
,你会得到“错误:trait MyBox接受类型参数”。
问题的第二部分与MyBox
或继承无关。由于完全相同的原因,这里的工作原理完全相同:
case class FruitBox[T](fruit: Int)
object FruitBox{
def apply[T](fruit: Int): FruitBox[T] = new FruitBox(fruit)
}
可以从代码中省略type参数,但右侧的表达式new FruitBox(fruit)
仍然是的正确类型 FruitBox[T]
。这是因为返回类型FruitBox[T]
可用于推断 =
- 符号后面的表达式类型。编译器会自动添加[T]
,因此上面的定义只是
def apply[T](fruit: Int): FruitBox[T] = new FruitBox[T](fruit)
这类似于以下示例:
var foo: Set[String] = Set.empty
即使方法empty
再次由类型参数化,也可以从声明的变量的类型推断出这个类型参数,以便代码有效地变为:
var foo: Set[String] = Set.empty[String]
类型推断会在其他几个案例中发挥作用,最突出的是:
new FruitBox(i)
作为参数出现在需要在该位置使用类型FruitBox[SomeType]
的参数的方法时,编译器将自动推断出new FruitBox(i)
实际上代表{{ 1}}。new FruitBox[SomeType](i)
中,编译器会自动将(new FruitBox(42) : FruitBox[String])
添加到[String]
调用中。