2016-01-22 2 views
0

Дано:Тип Параметры в `абстрактном class`

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 «s введите 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 «S extends Foo[Any].

Почему нет?

+1

Стоит отметить, что это возможно и в Java (но только после введения ковариантных типов возврата в Java 5), ​​а в Scala и Java это приводит к двум методам на уровне JVM: более конкретным один и синтетический метод, соответствующий внедренной сигнатуре. –

ответ

5

При переопределении члена абстрактного класса или признака, вы имеете право, чтобы сузить свой тип нечто большее, конкретный. Здесь нет , потому что вы полагаетесь на вывод типа для 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.

Ниже приведен пример без параметра типа:

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

g[AnyVal](y) это просто очень другой пример. Поскольку вы вручную подаете параметр типа AnyVal на номер g, вы просите компилятор убедиться, что y - AnyVal, но не имеет значения, является ли это более конкретным типом (более конкретный тип, возвращаемый методом, всегда будет вверх -cast для возвращаемого типа). В FooImpl2 вы просто меняете подпись f.

+0

Проблема для исправления вывода - https://issues.scala-lang.org/browse/SI-7212 –

3

Если у вас есть override метод, вы можете вернуть его более конкретному типу. В этой строке

override def f= "foo" 

вы не указали тип возвращаемого значения и был сделан вывод, что String

0

Подкласс может сузить возвращаемые типы методов, которые он переопределяет.
Обратный тип f в Foo[Any] - Any. FooImpl2 - это подтип Foo[Any], и вы не указали тип возвращаемого значения f s, поэтому компилятор сообщает, что это String, что является подтипом Any и, таким образом, удовлетворяет всем ограничениям.