Путаница с генериками Котлина

Я новичок в Kotlin, и я пытаюсь написать код, который делает что-то довольно простое, но я не могу понять, как использовать дженерики, чтобы заставить его работать.

Я имею свойство Handler которое представляет собой обработчик вещей. Я не могу изменить код для обработчика, поскольку он исходит из библиотеки .

 trait Handler<T> { fun handle(result: T) } 

Весь код, приведенный ниже, находится под моим контролем –

User является открытым классом, который имеет подклассы, такие как AdminUser и GuestUser и т. Д.

Характеристика, называемая AdminUserAction делает что-то для создания списка AdminUsers, а затем передает список обработчику List<AdminUser>

 trait AdminUserAction { fun then(handler: Handler<List<AdminUser>>) } 

Теперь я хочу передать AdminUserAction обработчик для User вместо AdminUser . Скажем, обработчик просто регистрирует имена пользователей и ничего не делает с определенными свойствами администратора.

 fun doIt(action: AdminUserAction, printAllNames: Handler<List<User>>) { action.then(printAllNames) } 

Однако этот код дает мне TypeMismatch .

Поскольку обработчик имеет тип List<T> и неизменен, предыдущий код должен быть полностью безопасным, однако компилятор не может понять это.

Если бы у меня был доступ к коду для Handler, я мог бы сделать следующее, и это сработает –

 trait Handler<in T> { fun handle(result: T) } 

Однако, как я уже говорил, я не могу изменить Обработчик, поскольку он исходит из библиотеки. Кроме того, кажется, что это сложно сделать, потому что тип Handler является полностью общим и должен использоваться для других видов обработчиков.

Я попробовал обработчик подкласса и использовал это –

 trait ListHandler<in T>: Handler<List<T>> { } 

Однако теперь я получаю сообщение об ошибке: «Параметр T объявлен как« in », но встречается в« инвариантном »положении в обработчике>

Я пытался –

 trait ListHandler<in T>: Handler<List<in T>> { } 

Но это дает мне больше ошибок.

Почему это так запутывает? И как я могу использовать generics, чтобы заставить предыдущий код работать?

Редактировать:

Я могу заставить его работать, написав общую функцию, которая преобразует Handler<List<User>> в Handler<List<AdminUser>>

 fun <T: User> fromGeneric(handler: Handler<User>): Handler<T> { return object: Handler<T> { override fun handle(result: List<T>) { handler.handle(result) } } } 

А потом –

 fun doIt(action: AdminUserAction, printAllNames: Handler<List<User>>) { action.then(fromGeneric(printAllNames)) } 

Но это кажется таким расточительным. Особенно посмотрите на тело функции преобразования из fromGeneric . Он ничего не делает! Тем не менее, я должен пройти через rigamarole, используя его каждый раз, только чтобы удовлетворить типы.

Есть ли способ лучше? Возможно ли технически сделать компилятор Kotlin умнее, чтобы этот тип фокуса не нужен?

Существует несколько решений:

Измените определение AdminUserAction на

 trait AdminUserAction { fun then(handler: Handler<in List<AdminUser>>) } 

или изменить определение AdminUserAction на

 trait AdminUserAction { fun then(handler: Handler<List<User>>) } 

или просто printAllNames как это

 fun doIt(action: AdminUserAction, printAllNames: Handler<List<User>>) { action.then(printAllNames as Handler<List<AdminUser>>) }