在列表上下文中使用kotlin类扩展时,解析父类的值而不是子类的值

时间:2019-05-31 07:23:30

标签: inheritance kotlin class-extensions

我正在使用Kotlin(1.3.20)中的类扩展,当在相同属性上扩展父类和子类,然后使用列表的实例时遇到了问题。

基本上发生的是子类的实例返回为父类的属性设置的值,而我不明白为什么会这样。 我希望下面代码中的第16行返回“ ext-specialthing”,但即使b [1]中的实例肯定是ExtSpecialThing类型,它也确实会返回“ ext-thing”。

我怀疑原因是扩展属性/扩展功能在后台运行的方式(顺便说一句:扩展功能也存在此问题);但我在这方面不是专家。

tl; dr:第16行失败...为什么?

import kotlin.test.*

fun main (args : Array<String>) {
    assertEquals("ext-special-thing", ExtSpecialThing().prop)

    var a = listOf(ImplThing(), ImplSpecialThing())
    assertTrue(a[0] is ImplThing)
    assertTrue(a[1] is ImplSpecialThing)
    assertEquals("impl-thing",         a[0].prop)
    assertEquals("impl-special-thing", a[1].prop)

    var b = listOf(ExtThing(), ExtSpecialThing())
    assertTrue(b[0] is ExtThing)
    assertTrue(b[1] is ExtSpecialThing)
    assertEquals("ext-thing",         b[0].prop)
    assertEquals("ext-special-thing", b[1].prop) // fails ... why?
}

// ======================================
open class ImplThing () {
    open val prop : String = "impl-thing"
}
class ImplSpecialThing : ImplThing() {
    override val prop : String = "impl-special-thing"
}

// -------------------------------------
open class ExtThing () {}
class ExtSpecialThing : ExtThing () {}

val ExtThing.prop : String get() = "ext-thing"
val ExtSpecialThing.prop : String get() = "ext-special-thing"

1 个答案:

答案 0 :(得分:3)

在官方docs中对此进行了描述:

  

我们要强调的是,扩展功能是静态分配的,即,它们不是由接收者类型虚拟的。这意味着所调用的扩展函数是由调用该函数的表达式的类型决定的,而不是由在运行时对该表达式求值的结果的类型决定的

所以这意味着以下将使您的测试成功:

assertEquals("ext-special-thing", (b[1] as ExtSpecialThing).prop)