Scala 抽象类中的类型参数`
鉴于: ,以及一个实现Scala 抽象类中的类型参数`,scala,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 res0具有类型Any,这是我所期望的,因为FooImpl使用Any作为其类型参数来Foo 并
scala> abstract class Foo[A] {
| def f: A
| }
defined class Foo
然后是一个实例
scala> class FooImpl extends Foo[Any] {
| def f: Any = "foo"
| }
defined class FooImpl
res0
具有类型Any
,这是我所期望的,因为FooImpl
使用Any
作为其类型参数来Foo
并且,考虑到第二个实现:
scala> new FooImpl().f
res0: Any = foo
以及实例化和调用f
:
scala> class FooImpl2 extends Foo[Any] {
| override def f= "foo"
| }
defined class FooImpl2
为什么res1
的类型是aString
鉴于,鉴于:
scala> new FooImpl2().f
res1: String = foo
我可以传递y
,一个Int
:
scala> def g[A](x: A):A = x
g: [A](x: A)A
到g
scala> val y: Int = 55
y: Int = 55
并返回一个AnyVal
最后,
scala> g[AnyVal](y)
res3: AnyVal = 55
按预期返回一个Int
然而,我本以为FooImpl2#f
会返回一个Any
给定FooImpl2
的扩展Foo[Any]
为什么不呢?当你重写一个方法时,你可以让它返回更具体的类型。在这一行
scala> g(55)
res5: Int = 55
您没有指定返回类型,它被推断为
String
当您重写抽象类或trait的成员时,您可以将其类型缩小为更具体的类型。这里不是这样,因为您依赖类型推断来覆盖def=“foo”,但实际上是覆盖def:String=“foo”
这是合法的:
override def f= "foo"
String
仍然符合类型参数A=Any
,但f
已在FooImpl2
中细化为String
下面是一个没有类型参数的示例:
abstract class Foo[A] {
def f: A
}
class FooImpl2 extends Foo[Any] {
override def f: String = "foo"
}
g[AnyVal](y)
是一个完全不同的例子。由于您手动将AnyVal
的类型参数提供给g
,因此您要求编译器确保y
是AnyVal
,但它是否是某个更具体的类型并不重要(方法返回的更具体的类型将始终向上转换为返回类型)。在FooImpl2
中,您只需更改f
的签名,子类就可以缩小它覆盖的方法的返回类型。Foo[Any]
中的f
的返回类型为Any
FooImpl2
是Foo[Any]
的子类型,您没有指定f
s返回类型,因此编译器推断它是String
,它是Any
的子类型,因此满足所有约束。值得注意的是,这在Java中也是可能的(但这只是因为在Java5中引入了协变返回类型),在Scala和Java中,它在JVM级别产生了两种方法:更具体的方法和与实现的签名匹配的合成方法。
abstract class A { def f: Any }
class B extends A { override def f: String = "a" }