2014-12-17 2 views
1

У меня есть следующий код:Scala полиморфизм

trait SuperX { 
val v: Int 
} 

class SubY(val v: Int, var z: SuperX) extends SuperX 

class SubZ(val v: Int) extends SuperX 

, и я не понимаю, почему это не возможно

var test: SuperX = new SubY(1, new SubZ(-1)) 
println(test.z.v) 

Если я пишу это как

var test = new SubY(1, new SubZ(-1)) 

тогда я не в состоянии сделать

test = test.z 

Я новичок в Scala, поэтому некоторые вещи довольно запутывают. Я знаю, что это возможно в Java с интерфейсом, а не с признаком.

Благодарим за помощь.

+0

Из любопытства, как бы вы сделали это на Java? – Dimitri

ответ

5

На этой линии:

var test: SuperX = new SubY(1, new SubZ(-1)) 

Вы явно Рассказывая компилятор, который test является SuperX. А тип SuperX не гарантирует наличие z, даже если этот конкретный экземпляр делает.

Когда вы пишете:

var test = new SubY(1, new SubZ(-1)) 

Тип test выводится в SubY, который имеет z, поэтому вызов test.z нормально.

+0

Каким образом вы измените структуру программы, чтобы иметь возможность сказать test = test.z? В последнем случае вы можете вызвать test.z, но не назначать его для тестирования (поскольку типом теста является SubY). В идеале я бы хотел, чтобы тест имел тип SuperX, и я хотел бы иметь возможность назначить его одному из своих подклассов (либо SubY, либо SubZ). Когда присваивание выполнено успешно, я хотел бы назвать некоторые его поля (которые встречаются только в подклассе z в случае SubY). – Robin64

+0

Вы не можете без использования типовых тестов. 'SuperX' также может быть' SubZ', который не имеет 'z', поэтому вы никогда не могли бы просто вызвать' test.z' (если он имеет тип 'SuperX'), без предварительной проверки, что это' SubY'. Например, путем сопоставления шаблонов в 'test' для' SubY', но это все равно заставит вас обрабатывать случай, когда он является 'SubZ'. –

+0

ОК, но разве это не цель полиморфизма, чтобы иметь возможность сделать это? Я мог бы сделать это на Java таким образом. Вот почему путь Скалы так запутан. – Robin64

1

РЕПЛ покажет, что результирующий тип после вызова:

scala> var test = new SubY(1, new SubZ(-1)) 

Это покажет, что ссылка выведенного типа является SubY и не SuperX, как вы ожидали. Scala делает предполагаемые типы, если вы их не предоставили. Ваш первый пример явно объявлен как SuperX

test: SubY = [email protected] 

Поэтому единственные методы и переменные, которые вы можете назвать те из SubY

Смежные вопросы