2016-10-01 2 views
2

Тип T ниже подтип Fruit. Apple также является подтипом Fruit. Итак, почему компилятор не принуждает Apple к T, когда используется титра типа. Зачем нам нужно явное литье, чтобы заставить его работать? Каковы правила принуждения при выводе типов?подтипирование и тип принуждения

trait Fruit 
case class Apple(id: String) extends Fruit 

type T <: Fruit 

val t: T = Apple("apple") // why doesn't the compiler coerce Apple to T? 

val t: T = Apple("apple").asInstanceOf[T] // works! 

ответ

1

Давайте немного упростим это. Замените T грушей и фруктами с плодом.

trait Fetus 
class Apple extends Fetus 
type Pear <: Fetus 

val t: Pear = new Apple() 

Мы объявили Fetus, тогда мы сказали "Яблоко Зародыш", а затем "Груша Зародыш". Наша логика до сих пор правильная. Но затем мы пытаемся «положить яблоко в коробку для груш». И вот наша ошибка.

Рассмотрим другой пример:

trait Fetus 
class Apple extends Fetus 
type Fruit >: Apple <: Fetus 

val t: Fruit = new Apple() 

Здесь мы объявили Fetus, тогда мы сказали «Яблоко Зародыш», а затем мы сказали, что «Плод-то посередине между Яблоком и Зародыша». Другими словами, мы построили следующую иерархию: Fetus -> Fruit -> Apple. Итак, теперь Apple является подтипом Fruit, и вы можете «положить яблоки в ящик для фруктов».

UPDATE:

Pear определенно не может быть и Apple, как кошка, не может быть собака, несмотря на оба они являются животными.Вы можете идти по иерархии только по вертикали, но не по горизонтали:

Creature 
    | 
Animal 
    _|_ 
/ \ 
Dog Cat 
     \ 
     White Cat 
+0

Итак, 'Pear <: Fetus' означает, что груша - это некоторый ** конкретный ** подтип' Fetus' и что ** конкретный ** подтип не 'Apple' ?? Но почему «Груша» не может быть «Apple»? Весь компилятор знает, что 'Pear' является подтипом' Fetus'. Это может быть или не быть Apple. – Samar

+0

Я обновил ответ –

+0

Спасибо за ваш ответ, теперь это имеет смысл. – Samar

1

Я думаю, ты путаешь смысл определения type T <: Fruit: Это абстрактного типа Defintion (в отличии от type T = Fruit который является типом псевдонимом). Абсолютные типы не создают класс T, который расширяет Fruit, скорее это абстрактная декларация , которая должна быть переопределена в каком-либо подклассе, который будет использоваться.

От Learning Scala, chapter 10:

... абстрактные типы спецификаций, которые могут решить к нулю, один или много классов. Они работают таким же образом к типу псевдонимов, но являются спецификации они абстрактны и не могут быть использованы для создания экземпляров

Обратите внимание, что декларация type T <: Fruit может находиться только в классе/признаке (не является объектом, ни TOP- определения уровня), потому что это бессмысленно до тех пор, пока этот класс/признак не будет расширен. Где он определен, он все еще абстрактный, и поэтому компилятор не может точно знать, что Apple расширяет его.

Пример использования такого определения:

trait Price { 
    type T <: Fruit 
    def printPrice(x: T): Unit 
} 

class ApplePrice extends Price { 
    override type T = Apple 
    override def printPrice(x: Apple): Unit = ??? 
} 

Здесь ApplePrice должны переопределить этот абстрактный тип с чем-то. Другой подкласс Price может переопределить это что-то другое (например, Banana extends Fruit), который должен дать понять, что выражение val t: T = Apple("apple") помещается в Price не может скомпилировать - для некоторых возможного простирающегося класса, T не Apple, а также не Apple расширить T.

+0

Спасибо, что указали на элемент типа абстрактного типа vs 'type. Но абстрактные типы, по-видимому, могут использоваться в качестве тиковых подписок (это похоже на то, что абстрактный тип действительно означает класс?) Кроме того, что вы думаете о рассуждениях Дмитрия? Это кажется интуитивным. – Samar

+1

Ответ Дмитрия совершенно верный, я просто предположил, что характер абстрактного определения был вопросом, нуждающимся в разъяснении. В конце концов, оба ответа вместе дают полную картину: будучи абстрактным, введите T _might_ в конечном итоге, являясь некоторым типом, который не является супертипом «Apple», поэтому компилятор не может позволить ему присваивать «Apple». –

+0

Ahh, компилятор мог только принуждать 'Apple' набирать' T', если 'T' был супертипом' Apple'. И это не выполняется, потому что 'T' может быть подтипом' Apple' или фактически ни тем, ни другим, помещенным горизонтально, как упоминалось в Dimitry. Спасибо, теперь все имеет смысл! – Samar