Интерфейс фабрики Kotlin с дженериками

У меня есть заводский интерфейс в моем коде Kotlin, например (используя Guava TypeToken ):

 interface ResultMapperFactory { fun <T> get(type: TypeToken<T>, context: MapperLookupContext): ResultMapper<T>? } 

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

 object StringFactory : ResultMapperFactory { override fun <T> get(type: TypeToken<T>, context: MapperLookupContext): ResultMapper<T>? { return if (type.rawType == String::class.java) MyStringMapper as ResultMapper<T> else null } } 

Это уродливо, но я победил его с помощью трюка. Во-первых, небольшая функция полезности для создания экземпляров TypeToken :

 inline fun <reified T> typeToken(): TypeToken<T> = object : TypeToken<T>() {} 

Теперь я добавил объект-компаньон к моему заводскому интерфейсу:

 companion object { inline operator fun <reified R> invoke(crossinline body: (TypeToken<R>, MapperLookupContext) -> ResultMapper<R>?): ResultMapperFactory { val t = typeToken<R>().type return object : ResultMapperFactory { override fun <T> get(type: TypeToken<T>, context: MapperLookupContext): ResultMapper<T>? { return if (type.isSubtypeOf(t)) body(type as TypeToken<R>, context) as ResultMapper<T>? else null } } } } 

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

 val stringMapper: ResultMapper<String> = TODO() val stringMapperFactory = ResultMapperFactory<String> { type, context -> stringMapper } 

Однако этот подход также разваливается, как только я хочу реализовать фабрику, которая принимает TypeToken<List<T>> и возвращает ResultMapper<List<T>> , потому что мне негде поставить этот параметр T

Я очень хочу услышать ваши предложения.

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

 private class ListResultMapper<out E>(private val elementMapper: ResultMapper<E>) : ResultMapper<List<E>> { /* ... */ } val listMapperFactory = ResultMapperFactory<List<*>> { type, context -> context.resultMapperFactory.get(type.elementType(), context)?.let { ListResultMapper(it) } } 
Intereting Posts
Доступ к информации из группы BroadcastReceiver в Android с использованием kotlin Не удалось найти класс databinding.FragmentBinding единичный тест с штормом апачей и кассандра: локальная топология, не потребляющая сообщение от кафки Как сделать активность размытой, когда она идет фон? Проблемы с переходом от фрагментатора / MapFragment к supportfragmentManager / SupportMapFragment Нельзя ли градировать проект построения, когда я добавляю класс ChatInformation kotlin, который расширяет RealmObject до моего проекта, где ошибка? Как установить стоимость недвижимости в Котлине Как объединить список в списке типа, в один неизменный список? Почему тексты не меняются в действии? Google Espresso: удалять данные пользователя по каждому тесту ViewPager во Фрагменте не работает второй раз Ошибка: не удалось найти или загрузить основной класс Hello.class Почему интеллектуальное сканирование сбрасывается для значения NULL после установки значения и проверки, является ли оно нулевым? Как получить значение ObservableField в android Сценарий тестового сценария с колллинским обратным вызовом лямбда