2016-07-05 2 views
2

Я новичок в scala. Я пытаюсь выяснить, как работают все отношения контравариантности. Я понимаю концепцию ковариации и инварианта, и я также знаю, как я буду реализовывать их на практике. Я также понимаю концепцию контравариантности (противоположность ковариации) и то, как она реализуется в признаке Function1 в Scala. Это дает абстракцию, не переопределяя реализации Function1 для разных классов. Но, я все еще не понимаю это, странно? Теперь, я почти там ... как я могу решить следующую проблему с контрвариации:Контравариантность в scala

class GarbageCan[-A] { 

    def doSomething(a: A): Unit ={ 
    // do something with 'a' of subtype that is not possible with the supertype 
    } 

} 

def setGarbageCanForPlastic(gc: GarbageCan[PlasticItem]): Unit = { 

} 

В приведенном выше примере извлекается из http://blog.kamkor.me/Covariance-And-Contravariance-In-Scala/. Действительно хорошее объяснение по этому вопросу. Иерархия выглядит следующим образом: Элемент (базовый класс) -> PlasticItem (подкласс) -> PlasticBottle (подкласс подкласса)

Функция setGarbageCanForPlastic принимает GarbageCan с типом PlasticItem. Поскольку параметризованные типа контравариантен, следующее утверждение вполне законно:

setGarbageCanForPlastic(new GarbageCan[Item]) 

Теперь функция йоЗотеЬЫпд принимает параметр типа, который контравариантен. Как я могу работать с этим типом, если я не знаю, является ли тип базовым классом «Item» или подклассом «PlasticItem»? Я могу сделать что-то, что допустимо в подклассе, а не в базовом классе. Если бы это был ковариантный параметр, это не проблема, подкласс наследует все от базового класса.

Я потерял это право? ... Надеюсь, кто-то может мне помочь.

+0

Почему вас беспокоит только 'GarbageCan [Item]'? Что мешает кому-то создать «GrabageCan [Option [List [Int]]]? Например? Игнорируйте дисперсию контравариантности на мгновение. Даже если это было просто «GrabageCan [A]», как вы думаете, что ваш 'doSomething' будет работать? – Dima

+0

Хороший вопрос ... Его следует использовать только как «тип» внутри тела? –

+1

Ну, я не уверен, что вы подразумеваете под «этим», и о чьем «теле», о котором вы говорите, поэтому я не знаю :) Суть в том, что вы _first_ придумали фактический прецедент, а _then_ см., если для этого подходит контравариантность/ковариация/инвариантность, а не наоборот. – Dima

ответ

1

Прежде всего, метод doSomething фактически не может ничего сделать, кроме как в основном отбрасывать a, так как он не знает, что такое A. Чтобы сделать его более полезным, вам понадобится связать, например, class GarbageCan[-A <: Item].

Теперь, предположим, setGarbageCanForPlastic(gc) звонки gc.doSomething(new PlasticItem). Поскольку A в GarbageCan[A] является контравариантным, мы имеем GarbageCan[Item] <: GarbageCan[PlasticItem] <: GarbageCan[PlasticBottle]. Действительно, вызов функции setGarbageCanForPlastic(new GarbageCan[Item])) безопасна как GarbageCan[Item] «s doSomething может обрабатывать любой Item включая PlasticItem, в то время как вызов setGarbageCanForPlastic(new GarbageCan[PlasticBottle])) небезопасно, потому что GarbageCan[PlasticBottle]» s doSomething не может быть в состоянии взять PlasticItem, которая не обязательно PlasticBottle.

+0

Отлично! Спасибо за вашу разработку. –