为什么SomeClass :: class是KClass <SomeClass>但是这个:: class是KClass <out SomeClass>

Gou*_*lov 6 reflection kotlin

我想打印我班级的属性值.

fun print() {
    val cl = this::class
    cl.declaredMemberProperties.filter {it.visibility != KVisibility.PRIVATE}.forEach {
        println("${it.name} = ${it.get(this)}")
    }
}
Run Code Online (Sandbox Code Playgroud)

当我尝试构建此代码时,我收到编译器错误:

Error:(34, 40) Kotlin: Out-projected type 'KProperty1<out SomeClass, Any?>' prohibits the use of 'public abstract fun get(receiver: T): R defined in kotlin.reflect.KProperty1'
Run Code Online (Sandbox Code Playgroud)

当我this改为班级名字时,SomeClass一切都很好

fun print() {
    val cl = SomeClass::class
    cl.declaredMemberProperties.filter {it.visibility != KVisibility.PRIVATE}.forEach {
        println("${it.name} = ${it.get(this)}")
    }
}
Run Code Online (Sandbox Code Playgroud)

所以问题是,编译器换型的this::class,以KClass<out SomeClass>代替使用KClass<SomeClass>.知道为什么会这样吗?

hot*_*key 7

这种差异的原因在于,当您使用SomeClass::class引用时,它肯定是表示的类令牌SomeClass而不是其可能的派生类之一,因此它KClass<SomeClass>没有类型投影.

但是this::class在函数openabstract类函数或扩展函数中编写可以返回派生类的类标记,因此,为了确保类型安全,类型为out-projected:KClass<out SomeClass>表示实际类型参数可以是SomeClass或其子类型.

例:

open class A {
    fun f() {
        println(this::class) // KClass<out A> because it can be KClass<B>
    }
}

class B : A()

B().f()
Run Code Online (Sandbox Code Playgroud)