如何在Kotlin中迭代类属性

hl0ma9xz  于 2023-06-24  发布在  Kotlin
关注(0)|答案(1)|浏览(114)

我有一个抽象类ConfigGroup,它有一个超类ConfigElement。在ConfigElement中,定义了toJson()方法。ConfigGroup将覆盖此方法。
目前ConfigGroup中的toJson()看起来像这样:

override fun toJson(): JsonObject {
        val map: HashMap<String, JsonObject> = HashMap()
        for (child in this::class.declaredMemberProperties) {
            map[child.name] = (child.get(this) as ConfigElement).toJson()
        }
        return JsonObject(map)
    }

但是当我试图编译它时,我得到Type mismatch: inferred type is ConfigGroup but Nothing was expected
我有点困惑,因为它几乎与Kotlin: Iterate over components of object中的示例相同。唯一的区别是,我试图从同一个类中获取属性,因此必须使用this关键字。

ttp71kqs

ttp71kqs1#

这里的问题是,Kotlin编译器不够聪明,无法理解您对::classget()使用的是完全相同的对象。在这种特定情况下,这是类型安全的,可以被允许。然而,在更一般的情况下,从对象获取KProperty并使用它来获取值不是类型安全的,Kotlin故意不允许它。
我们可以用与其他情况相同的方式来解决这个问题,即编译器不理解代码是类型安全的-通过进行未检查的强制转换:

(child as KProperty1<ConfigGroup, *>).get(this) // or even: KProperty1<Any, *>

但是等等,为什么获取类型为Animal的变量的成员,然后对animal示例使用它不是类型安全的呢?难道不能保证animal拥有动物所需的所有成员吗?不完全是我们可以从狗身上获得一些成员,然后用它们来对付猫,因为它们都是动物。

fun main() {
    printProperties(Dog(), Cat())
}

fun printProperties(animal1: Animal, animal2: Animal) {
    for (prop in animal1::class.declaredMemberProperties) {
        println("${prop.name}: ${(prop).get(animal2)}") // isn't typesafe, so doesn't compile
    }
}

printProperties内部,animal1animal2都是Animal类型,但它们的运行时类型不同,因此从animal1获取属性并将其用于animal2不是类型安全的。
Kotlin通过使用方差来防止这种类型的问题。如果我们执行Animal::class,我们得到一个KClass<Animal>,所以我们可以使用这个类来消费动物对象。但是如果我们做animal::class,我们得到KClass<out Animal>,因为我们不能确定animal的确切类型。KClass<out Animal>基本上说我们有一个KClass的动物或其亚型之一,我们不知道是哪一个。默认情况下,我们不能使用这个KClass来消费动物对象。
在您的特定情况下,可以保证我们从完全相同的运行时类型获取KClass,然后尝试使用,因此这是类型安全的,我们可以安全地使用未经检查的强制转换。

相关问题