Как разрешить обобщение шаблонов функций для системы сигнал / слот? - PullRequest
0 голосов
/ 09 сентября 2018

Я пытаюсь разработать упрощенную систему сигналов / слотов в Котлине. Вот что у меня есть:

open class Signal<T : Function<Unit>>() {
    val callbacks = mutableListOf<T>()

    open fun addCallback(slot: T) {
        callbacks.add(slot)
    }

    open fun emit(vararg params: Any) {
        for(call in callbacks) {
            call(*params)
        }
    }
}

fun test(myarg: Int) = println(myarg)

fun main(args: Array<String>) {
    val myevent = Signal<(Int) -> Unit>()
    myevent.addCallback(::test)
    myevent.emit(2)
}

Идея состоит в том, чтобы создать экземпляр Signal вместе с универсальным шаблоном, чтобы определить, какие параметры используются для обратных вызовов. Обратные вызовы могут быть добавлены к Signal. Наконец, всякий раз, когда Signal должен быть ... хорошо ... "сигнализирован", используется метод emit. Этот метод передает все параметры соответствующим обратным вызовам, если необходимо.

Проблема в том, что этот код приводит к следующей ошибке:

kotlin\Signal.kt:30:4: error: expression 'call' of type 'T' cannot be invoked as a function. The function 'invoke()' is not found

Соответствующая строка: call(*params)

Любые рекомендации о том, как с этим справиться?

1 Ответ

0 голосов
/ 09 сентября 2018

Это потому, что Function является пустым интерфейсом ( источник ).

Различные типы функций, которые на самом деле имеют операторы invoke, определены по одномуна один здесь , как Function0, Function1 и т. д.

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

open class Signal<T> {
    val callbacks = mutableListOf<(T) -> Unit>()

    open fun addCallback(slot: (T) -> Unit) {
        callbacks.add(slot)
    }

    open fun emit(param: T) {
        for (call in callbacks) {
            call(param)
        }
    }
}

fun test(myarg: Int) = println(myarg)

fun main(args: Array<String>) {
    val myevent = Signal<Int>()
    myevent.addCallback(::test)
    myevent.emit(2)
}

(Обратите внимание, что вы можете заменить оба использования (T) -> Unit здесь на Function1<T, Unit>.)

...