我尝试在复杂的场景(使用泛型等)中通过反射读取属性的值。但我总是因为这个错误而失败:
Type mismatch: inferred type is ReflectionTest.Person but Nothing was expected
所以我能够将其缩小到以下问题:
class ReflectionTest {
data class Person(val firstname: String, val lastname: String)
@Test
fun b() {
val person = Person("Donald", "Duck")
val a = Person::class
val b = person::class
val personAfirstname = a.memberProperties.find { it.name == "firstname" }?.get(person) // this works fine
val personBfirstname = b.memberProperties.find { it.name == "firstname" }?.get(person) // compiler error: Type mismatch: inferred type is ReflectionTest.Person but Nothing was expected
}
}
有人可以解释一下,为什么编译器在最后一行需要
Nothing
以及如何解决这个问题?
在我的调查过程中,我遇到了 Error Kotlin:类型不匹配:推断类型是 T?但什么也没预料到。但即便如此,我也无法解决问题。
虽然
Person::class
的类型是 KClass<Person>
,但 person::class
的类型是 KClass<out Person>
。
与
TypeName::class
不同,它只能评估一件事 - 代表 KClass
的 TypeName
- expression::class
可以评估不同的 KClass
实例,具体取决于 expression
的运行时类型。例如:
fun foo(x: Any) {
println(x::class)
}
fun main() {
foo(Any()) // prints Any
foo(1) // prints Int
foo("bar") // prints String
}
x::class
的类型不能是KClass<Any>
(又名Any::class
)。 x
在运行时可能是其他类的实例。它必须是 KClass<out Any>
,因为它可能会计算为 Int::class
(类型为 KClass<Int>
)或 String::class
(类型为 KClass<String>
)等。
在您的情况下,
Person
是一个数据类,因此无法继承它,因此person
实际上不能是除了Person
之外的任何对象的实例。 Kotlin 不够聪明,知道这一点,所以 person::class
的类型是 KClass<out Person>
,就像任何其他 expression::class
表达式一样。
因此,就 Kotlin 而言,
person::class
可能是 Person
的子类,因此在获取属性值时不能传递 Person
。毕竟,如果 find
找到仅在 Person
的子类中可用的属性怎么办? (当然,我们人类知道这不会发生。)
expression::class
类似于 Java 的 Object.getClass
方法。另请参阅 Why does getClass return a Class? 有关为什么 getClass
返回 Class<? extends T>
(类似于 KClass<out T>
)的讨论。