如何在Kotlin中实现KFunctionN?

时间:2019-02-12 11:17:09

标签: reflection kotlin

如果我定义

class MyF : KFunction0<Int> {
    override val name: String = "f"
    override fun invoke() = 42

    override val annotations: List<Annotation>
        get() = TODO()
    ....
}

我会写

val f0: KFunction0<Int> = MyF()
assertEquals("f", f0.name)

但如果我尝试

assertEquals(42, f0())

我得到java.lang.ClassCastException: MyF cannot be cast to kotlin.jvm.functions.Function0

如何定义自己的KFunction0实现?

我无法使用() -> Int,因为我需要name属性。

我正在使用Kotlin 1.3.21。

另外-看来我可以跑步

val f02 = MyF()
assertEquals(42, f02())

我的实际用例是Can I convert a Kotlin KFunction1 to a KFunction0 by applying the argument?

2 个答案:

答案 0 :(得分:4)

从Kotlin JVM显式实现内部类绝对不是一个好主意。由于某种原因,您在IntelliJ或Android Studio中没有该类的代码完成

您可以改为使用可调用引用,以使Kotlin编译器为您生成所有必需的类。 https://kotlinlang.org/docs/reference/reflection.html#callable-references

NotApplicable

好处-将来的Kotlin版本不太可能破坏该代码(并可能破坏您的继承者类)

如果您需要一个更长的名称,可以这样声明

    fun myfun() = 42
    val kFunction = ::myfun


    println(kFunction.name)
    println(kFunction())

答案 1 :(得分:1)

在Kotlin 1.2中,我没有找到KFunction0<T>,但只有KFunction<T>,我能够做你想做的事情:

import kotlin.reflect.*
import kotlin.test.assertEquals

class MyKF : KFunction<Int>{ // In Kotlin 1.3 you can extend KFunction0<Int>

    override val annotations: List<Annotation>
        get() = listOf()
    override val isAbstract: Boolean
        get() = false
    override val isExternal: Boolean
        get() = false
    override val isFinal: Boolean
        get() = true
    override val isInfix: Boolean
        get() = false
    override val isInline: Boolean
        get() = false
    override val isOpen: Boolean
        get() = false
    override val isOperator: Boolean
        get() = false
    override val isSuspend: Boolean
        get() = false
    override val parameters: List<KParameter>
        get() = listOf()
    override val typeParameters: List<KTypeParameter>
        get() = listOf()

    /**
     * I am not sure how get proper return type. So... This KFunction will return kotlin.Number.
     */
    override val returnType: KType
        get() = Int::class.supertypes[0]
    override val visibility: KVisibility?
        get() = KVisibility.PUBLIC

    override fun call(vararg args: Any?): Int {
        return 0
    }

    override fun callBy(args: Map<KParameter, Any?>): Int {
        return 0
    }

    override val name: String
        get() = "f"

    // Sience Kotlin 1.3
    override fun invoke(): Int {
        return 0
    }
}

fun main(args: Array<String>) {
    val kf = MyKF()
    assertEquals("f", kf.name)
    assertEquals(0, kf.call())

    println(kf.returnType)
    println(kf.name)
    println(kf.call())
    pritnln(kf.invoke())
}

稍后我将把Kotlin更新到1.3,然后我将回答完整(如果它在Kotlin 1.3中可用)。

那么您的问题在哪里?也许(只是幸运的猜测)基于returnType之类的覆盖方法的检查类型?

编辑:

迁移到Kotlin 1.3之后,我可以扩展KFunction0<Int>而不是KFunction<Int>。唯一的更改-我的班级也必须覆盖invoke(): Int。仍然有效!

Edit2:

我不确定我是在IDE中没有看到KFunction0还是在1.3以下的Kotlin中不存在。