在`abstract class`

时间:2016-01-22 15:05:42

标签: scala

假设:

scala> abstract class Foo[A] {
     |   def f: A
     | }
defined class Foo

,以及实施

scala> class FooImpl extends Foo[Any] {
     |   def f: Any = "foo"
     | }
defined class FooImpl

然后是实例化

scala> new FooImpl().f
res0: Any = foo

res0的类型为Any,正如我所期望的那样FooImpl使用Any作为Foo的类型参数。

并且,鉴于第二个实施:

scala> class FooImpl2 extends Foo[Any] {
     |   override def f= "foo"
     | }
defined class FooImpl2

并实例化并调用f

scala> new FooImpl2().f
res1: String = foo

为什么res1输入String

鉴于:

scala> def g[A](x: A):A = x
g: [A](x: A)A

我可以传递yInt

scala> val y: Int = 55
y: Int = 55

g

scala> g[AnyVal](y)
res3: AnyVal = 55

并取回AnyVal

最后,

scala> g(55)
res5: Int = 55

按预期返回Int

但是,我希望FooImpl2#f返回Any给定FooImpl2的{​​{1}}。

为什么不呢?

3 个答案:

答案 0 :(得分:6)

当您覆盖抽象类或特征的成员时,您可以将其类型缩小为更具体的类型。它在这里没有出现,因为您依赖于override def f = "foo"的类型推断,但它真的是override def f: String = "foo"

这是合法的:

abstract class Foo[A] {
  def f: A
}

class FooImpl2 extends Foo[Any] {
  override def f: String = "foo"
}

String仍然符合类型参数A = Any,但f已经FooImpl2改进为String

以下是没有type参数的示例:

abstract class A { def f: Any }
class B extends A { override def f: String = "a" }

g[AnyVal](y)是一个非常不同的例子。由于您手动将AnyVal的类型参数提供给g,因此您要求编译器确保yAnyVal,但是如果它不重要它是一些更具体的类型(方法返回的更具体的类型将始终向上转换为返回类型)。在FooImpl2中,您只需更改f的签名。

答案 1 :(得分:3)

当你override方法时,你可以让它返回更具体的类型。在这一行

override def f= "foo"

您未指定返回类型,并且推断为String

答案 2 :(得分:0)

子类可以缩小它覆盖的方法的返回类型 fFoo[Any]的返回类型为AnyFooImpl2Foo[Any]的子类型,您没有指定f的返回类型,因此编译器推断它是String,这是Any的子类型1}}因此满足所有约束。