Kotlin: хранить любой тип ссылки на функцию в переменной - PullRequest
0 голосов
/ 02 ноября 2018

Возможно ли иметь переменную, которая может содержать функцию любого типа.

Как:

    fun method1(par: Boolean){}
    fun method2(par: Boolean) : Int{return 1}
    fun method3(par: Boolean, par2: Boolean) : Int{return 1}

    var funtionHolder : ((Any)->Any) ?= null  //What should I write here?? so to hold any type of function

   fun method4(){
        .........
        funtionHolder = ::method1  //getting compile time error
        .........
        funtionHolder = ::method2  //getting compile time error
        .........
        funtionHolder = ::method3  //getting compile time error
    }

После удержания function_reference мне нужно вызвать его позже. Так что мне нужно держать его тип параметра и состояние также.

Ответы [ 3 ]

0 голосов
/ 02 ноября 2018

Нет. Kotlin - статический типизированный язык и не позволяет этого. Иначе, что происходит, когда это называется?

functionHolder->invoke(3)

а когда functionHolder назначается лямда, которая не принимает параметр?

0 голосов
/ 02 ноября 2018

Со ссылкой на ответ Джейсона добавлен дополнительный код для хранения состояния функции с использованием vararg и оператора распространения (*) .

    var functionHolder: KFunction<Any> ?= null
    var paramsHolder : Array<out Any?> ?= null

    fun hold(functionReference : KFunction<Any>, vararg args : Any?) {
        this.functionHolder = functionReference
        this.paramsHolder = args
    }

    fun release() {
        if (functionHolder != null) {
            if (paramsHolder != null) {
                functionHolder?.call(*paramsHolder!!)
            } else {
                functionHolder?.call()
            }
        }
    }

......

    fun method3(par: Boolean, par2: Boolean) : Int{return 1}

......

    hold(::method3, true, false)
    release()//it works
0 голосов
/ 02 ноября 2018

Вы можете хранить их в KFunction<Any> или его суперклассе KCallable<Any>, потому что вы ничего не знаете о списке параметров и ничего о типе возвращаемого значения, поэтому вам нужно идти к чему-то, что может ссылаться на этом уровне абстракции. Затем эти экземпляры можно вызывать более широко, используя методы call() или callBy(). ( для этого требуется зависимость kotlin-reflect ). Чтобы сделать что-то более безопасное и вызвать как обычную функцию, вам придется вернуться к конкретному типу функции позже.

Если вы хотите избежать этого, вам нужно объединить свои подписи с чем-то, на что вы можете указать, с помощью другого типа функции (например, KFunction1 или KFunction2). В противном случае, как вы это называете, что вы будете делать с этим, будет зависеть от вас, потому что вы стерли всю информацию, которая позволяет вам легко вызывать функцию.

val functionHolder1: KFunction<Any> = ::method1 // success!
val functionHolder2: KFunction<Any> = ::method2 // success!
val functionHolder3: KFunction<Any> = ::method3 // success!

Затем вы можете создать класс DeferredFunction, который будет хранить их вместе с параметрами, которые вы хотите передать позже, и затем вызывать его всякий раз в будущем.

class DeferredFunction(val function: KFunction<Any>, vararg val params: Any?) {
    @Suppress("UNCHECKED_CAST")
    operator fun <T> invoke(): T {
        return function.call(params) as T
    }
}

fun whatever(name: String, age: Int): String {
    return "$name of age $age"
}

val functionHolder = DeferredFunction(::whatever, "Fred", 65)

println(functionHolder<String>()) // "Fred of age 65"

Вам не нужен универсальный тип возвращаемого значения для функции invoke, и вы можете просто заставить его вернуть Any или вызвать его как functionHolder<Any>(), но было бы хорошо, если вы знаете, что ожидать для возврата. Вы можете решить, что делать там, исходя из вашего фактического варианта использования. Также нет необходимости в специальном регистре для параметров, просто не передавайте их, т.е. DeferredFunction(::otherFunc)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...