Тревога Котлина и дженериков

У меня есть некоторые Drawers с дженериками:

 abstract class BaseGeoDrawer<KEY : Any, GEO : Any, ITEM : Any> abstract class BasePolygonDrawer<KEY : Any, ITEM : Any>: BaseGeoDrawer<KEY, Polygon, ITEM> class TeamAreaDrawer : BasePolygonDrawer<String, Team> abstract class BaseMarkerDrawer<KEY : Any, ITEM : Any> : BaseGeoDrawer<KEY, Marker, ITEM> class TeamPositionDrawer : BaseMarkerDrawer<String, Team> 

Тогда у меня есть controller который принимает эти Drawers , помещая их в ArrayList

 private val drawers = ArrayList<BaseGeoDrawer<Any, Any, Any>>() open fun addGeoDrawer(drawer: BaseGeoDrawer<Any, Any, Any>) { drawers.add(drawer) } 

И позже вызывающие методы в этих Drawers

 //Method in controller private fun onMarkerClicked(marker: Marker): Boolean { return drawers.any { it.onGeoClicked(marker) } } //Method in BaseGeoDrawer fun onGeoClicked(geo: GEO): Boolean 

Проблема возникает в этой строке

 teamAreaDrawer = TeamAreaDrawer(this) mapController.addGeoDrawer(teamAreaDrawer) 

Android Studio не позволит, рассказывая мне

 Type mismatch. Required: BaseGeoDrawer<Any, Any, Any> Found: TeamAreaDrawer 

Я попытался использовать для drawers

 private val drawers = ArrayList<BaseGeoDrawer<out Any, out Any, out Any>>() 

Но тогда onMarkerClicked не будет компилироваться со следующей ошибкой

 Out-projected type BaseGeoDrawer<out Any, out Any, out Any> prohibits the use of 'public final fun onGeoClicked(geo: GEO) defined in mypackage.BaseGeoDrawer' 

    Проблема здесь в том, что вам нужен GEO как контравариантный параметр типа в BaseGeoDrawer для использования onGeoClicked(GEO) но ArrayList<BaseGeoDrawer<Any, Any, Any>> является инвариантным по своему типу. Это означает, что вы не можете добавить ничего, кроме BaseGeoDrawer<Any, Any, Any> . Если вы попытаетесь использовать типы BaseGeoDrawer как ковариантные, он не будет компилироваться, потому что вам нужно, чтобы он был контравариантным, когда вы вызываете onGeoClicked(GEO) .

    Учитывая, что до сих пор в Котлине параметр типа не может быть бивариантным , единственный способ сделать это – сделать непроверенный бросок.

    В этом конкретном случае вы можете:

     val teamAreaDrawer = TeamAreaDrawer(this) as BaseGeoDrawer<Any, Any, Any> mapController.addGeoDrawer(teamAreaDrawer) 

    Если вы думаете об этом, на Java, вы бы сделали то же самое, потому что у вас было бы:

     List<BaseGeoDrawer> drawers = new ArrayList<>(); public void example() { TeamAreaDrawer teamAreaDrawer = new TeamAreaDrawer(); drawers.add(teamAreaDrawer); // This is an unchecked cast. drawers.get(0).onGeoClicked("Example"); } 

    Я рекомендую вам больше узнать о различиях здесь .

    Intereting Posts
    Вложенные аннотации в Котлине Ошибка Adobe flashplayer или HTML5 Browser с поддержкой WebGL или CSS3D, необходимой для виртуального тура в Android Kotlin Decompiler генерирует ошибочный код – можно ли предотвратить? Предоставление общего экземпляра в Kotlin & Guice Как установить свойство lateinit Kotlin для null Как написать надлежащий тест для реактивного репозитория интерфейса, который возвращает Observable только в том случае, когда есть какое-то событие, как издеваться над запуском этого события Как передать двоичный массив в качестве аргумента функции в Котлине Возвращает результат запроса postgresql в функции нет конструктора по умолчанию для объекта JPA с Kotlin даже с плагином noarg NPE по конструктору и суперклассу Как отобразить уведомление в приложении, которое не хранится в ящике уведомлений à la Snapchat как убрать DialogFragment из lambda, указанного в caller Kotlin добавить Google Fit distance (DataPoint выходит за пределы диапазона) ReactiveStreams NPE при использовании publishOn с пользовательским издателем Как «Список <MyClass> :: clas.java` в kotlin