假设:
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
我可以传递y
,Int
:
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}}。
为什么不呢?
答案 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
,因此您要求编译器确保y
为AnyVal
,但是如果它不重要它是一些更具体的类型(方法返回的更具体的类型将始终向上转换为返回类型)。在FooImpl2
中,您只需更改f
的签名。
答案 1 :(得分:3)
当你override
方法时,你可以让它返回更具体的类型。在这一行
override def f= "foo"
您未指定返回类型,并且推断为String
答案 2 :(得分:0)
子类可以缩小它覆盖的方法的返回类型
f
中Foo[Any]
的返回类型为Any
。 FooImpl2
是Foo[Any]
的子类型,您没有指定f
的返回类型,因此编译器推断它是String
,这是Any
的子类型1}}因此满足所有约束。