Расширения класса kotlin разрешают значение родительского класса вместо дочерних при использовании в контексте списка - PullRequest
1 голос
/ 31 мая 2019

Я работаю с расширениями классов в Kotlin (1.3.20), и я сталкиваюсь с проблемой, когда расширяю родительский класс и дочерний класс на одно и то же свойство, а затем использую экземпляры этих списков.

В основном происходит то, что экземпляр дочернего класса возвращает значение, установленное для свойства родительского класса, и я не понимаю, почему это так. Я ожидаю, что строка 16 в приведенном ниже коде вернет «ext-special-thing», но она возвращает «ext-thing», хотя экземпляр в b [1] определенно имеет тип ExtSpecialThing.

Я подозреваю, что причина в том, что свойства extension / extension-functions работают под капотом (кстати: эта проблема существует и с функциями расширения); но я не эксперт в этом отношении.

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 Ответ

3 голосов
/ 31 мая 2019

Это описано в официальных документах :

Мы хотели бы подчеркнуть, что функции расширения отправляются статически, то есть они не являются виртуальными в зависимости от типа получателя. Это означает, что вызываемая функция расширения определяется типом выражения, для которого вызывается функция, а не типом результата вычисления этого выражения во время выполнения .

Это значит, что следующий тест сделает ваш тест успешным:

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