Kotlin, generics и функция, которая может не иметь аргументов

Я пытаюсь обобщить шаблон с очень распространенным рисунком, и Котлин приносит мне мучительную близость.

Я создал класс, который служит менеджером прослушивателя, следующим образом:

class GenericListenerSupport <EventArgumentType, ListenerFunction: (EventArgumentType) -> Unit> { private val listeners = mutableListOf<ListenerFunction>() fun addListener(listener: ListenerFunction) { listeners.add(listener) } fun removeListener(listener: ListenerFunction) { listeners.remove(listener) } fun fireListeners(argument: EventArgumentType) { listeners.forEach { it.invoke(argument) } } } 

и его можно использовать следующим образом:

 class ExampleWithArgument { private val listenerSupport = GenericListenerSupport<String, (String)->Unit>() fun exampleAdd() { listenerSupport.addListener({ value -> System.out.println("My string: "+value)}) } fun exampleFire() { listenerSupport.fireListeners("Hello") } } 

Все идет нормально. Но что, если у слушателя нет аргументов? Или растягивание еще больше, несколько параметров.

Я могу скреститься с этим:

 class ExampleWithNoArgument { private val listenerSupport = GenericListenerSupport<Nothing?, (Nothing?)->Unit>() fun exampleAdd() { listenerSupport.addListener({ System.out.println("I've got no argument")}) } fun exampleFiring() { listenerSupport.fireListeners(null) } } 

но он пахнет, и, очевидно, это бесполезно для нескольких параметров.

Есть ли лучший способ снять это? например, что-то, поддерживающее эту концепцию:

 private val listenerSupport = GenericListenerSupport<???, (String, Double)->Unit>() 

Поскольку ваш GenericListenerSupport объявляет параметр типа EventArgumentType и ожидает его экземпляр в fun fireListeners(argument: EventArgumentType) , я сомневаюсь, что вы можете поддерживать несколько аргументов чистым способом. Вместо этого я бы предложил использовать класс данных (а это не так много дополнительного кода), как чистый и безопасный тип для переноса нескольких значений:

 data class MyEvent(val id: String, val value: Double) private val listenerSupport = GenericListenerSupport<MyEvent, (MyEvent) -> Unit>() 

Что касается передачи никакого значения, вы также можете использовать Unit , тип, который имеет ровно одно значение Unit :

 listenerSupport.fireListeners(Unit) 

Система типов и разрешение не позволят вам передавать аргументы, где ожидается один, но, как предложил @Ruckus T-Boom , вы можете сделать расширение для прослушивания прослушивателей без значения, где ожидается Unit :

 fun GenericListenerSupport<Unit>.fireListeners() = fireListeners(Unit) 

Немного не по теме, но я думаю, вы можете упростить тип, если вам не нужны пользовательские типы функций и (EventArgumentType) -> Unit Достаточно (EventArgumentType) -> Unit :

 class GenericListenerSupport<EventArgumentType> { /* Just use `(EventArgumentType) -> Unit` inside. */ } 
Intereting Posts
Java generics в Kotlin: используйте Java raw type в качестве параметра метода в Kotlin Встроенная функция не может получить доступ к непубличным API: @PublishedApi vs @Suppress vs @JvmSynthetic kotlin null указатель execption Оператор звездочки Kotlin до имени переменной или оператора Spread в Котлине Уведомление о запросе в Realm не срабатывает с использованием Kotlin Анко. Выполнение изменений асинхронного макета Android Firebase auth: класс дескриптора локального модуля для com.google.android.gms.crash и com.google.firebase.auth не найден Использовать расширение Kotlin в классе android java Jna, указатель уже сопоставлен с интерфейсом Proxy Не удалось получить данные из базы данных sqlite Загружать ресурс из локального каталога без класса Как преобразовать String в Long в Kotlin? Возвращаемое значение для переменной, которая, по-видимому, может быть нулевой, но на самом деле не может Разница между различными функциями verifySignatures в тестировании блока Corda Spring ConfigurationProperties и Kotlin?