Отображение лямбды для класса в HashMap

#kotlin #generics

#kotlin #обобщения

Вопрос:

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

 sealed class HttpErrors(open var errorMessage: String = String()) : Throwable()
class UnauthorizedError(override var errorMessage: String) : HttpErrors()
class BadRequestError(override var errorMessage: String) : HttpErrors()

fun handleErrors(actions: HashMap<Class<out Throwable>, () -> Unit>){
...
}
  

Я вставляю в map и передаю его в функцию:

 override fun getItems() {
        ...
        val actions = hashMapOf(BadRequestError::class.java to {presenter.log("Info")})
        ...
        .onDefaultSchedulers(actions)
  

И мой, который получает карту:

 fun <T> Single<T>.onDefaultSchedulers(actions: HashMap<Class<in Throwable>, () -> Unit>): Single<T> 
  

Но редактор жалуется, говоря:

 Type mismatch.
Required:
kotlin.collections.HashMap<Class<in Throwable>, () → Unit> /* = java.util.HashMap<Class<in Throwable>, () → Unit> */
Found:
kotlin.collections.HashMap<Class<BadRequestError>, () → Unit> /* = java.util.HashMap<Class<BadRequestError>, () → Unit> */
  

Я не понял, на что жаловаться, если BadRequestError наследуется от Throwable.

Комментарии:

1. in означает контравариантный. Допустимая иерархия типов инвертирована из чего-то, что имеет ковариантный out тип (как List всегда было). Например, функция, которая работает с <in T: Int> , не может работать с супертипами Int , такими как Number , потому что она может использовать функцию, Int которой Number нет.

2. Исправлено @Tenfour04. Даже без out я получаю ту же ошибку.

Ответ №1:

Это минимальная версия вашего кода, которая воспроизводит ошибку, которую вы наблюдали:

 /* does not compile */

sealed class HttpErrors : Throwable()

class BadRequestError : HttpErrors()

fun onDefaultSchedulers(actions: HashMap<Class<out Throwable>, () -> Unit>) {}

fun getItems() {
    val actions = hashMapOf(BadRequestError::class.java to {})
    onDefaultSchedulers(actions)  // <- type mismatch
}
  

Чтобы заставить его работать, actions параметру onDefaultSchedulers требуется двухуровневая ковариация,

  1. на внешнем Class<...> и
  2. на внутреннем Throwable .

Итак, если вы объявите это как HashMap< out Class<out Throwable>, ... , код компилируется:

 /* compiles */

sealed class HttpErrors : Throwable()

class BadRequestError : HttpErrors()

fun onDefaultSchedulers(actions: HashMap<out Class<out Throwable>, () -> Unit>) {}

fun getItems() {
    val actions = hashMapOf(BadRequestError::class.java to {})
    onDefaultSchedulers(actions)
}