如何解决信号/插槽系统的功能模板泛型?

时间:2018-09-09 11:19:07

标签: kotlin callback signals-slots

我正在尝试在Kotlin中开发一种简单的信号/插槽系统。这是我到目前为止的内容:

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 :(得分:1)

这是因为Function是一个空接口(source)。

实际上具有invoke运算符的各种函数类型都被here一一定义为Function0Function1等。

我认为您无法创建一个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>。)