Kotlin:多种类型的智能投射

时间:2019-04-15 10:41:15

标签: kotlin

我正在为antlr构建从CST到AST的映射器,因此需要大量*Context类来映射到它们的核心AST节点。 我有ANTLR生产的类和我的映射器方法:

// Demo data:
open class Super
class Sub0: Super
class Sub1: Super
// Mappers:
fun map(a: Super) = println("Super")
fun map(a: Sub0) = println("Sub0")
fun map(a: Sub1) = println("Sub1")

然后,我想按以下方式使用它:

listOf(Super(), Sub0(), Sub1()).forEach {
    when (it) {
        is B, is C -> { print('*'); map(it) }
        else -> map(it)
    }
}

我希望it被智能广播到Sub0或Sub1并调用正确的map,但这给出了:

Super
*Super
*Super

这表示它选择了正确的路径,但未进行自动广播。 这种方法行之有效,但随着您拥有越来越多的SubX,这种方法就变得越来越长:

when (it) {
    is Sub0 -> {
        print("*");
        map(it)
    }
    is Sub1 -> {
         print("*");
         map(it)
    }
    else -> map(it)
}

我知道我可以使用一些反射形式的黑魔法,并在所有map(X)上进行迭代,然后使用一些“聪明的把戏”来选择合适的,但是我宁愿不这样做。 ;)

1 个答案:

答案 0 :(得分:4)

智能强制转换不起作用,因为when分支is B, is C -> map(it)中的代码仅进行了一次类型检查。对于一种类型和另一种类型,没有将其编译为两组不同的指令。编译器需要为it推断一种类型,而这两种情况都可以使用。

Sub0Sub1的类型均不能选择it的类型,因为选择其中一个不会覆盖另一个。因此,编译器选择Sub0Sub1的最小公共超类型,即Super。然后,以map的静态已知类型Super来解决对it的调用。

所以确实,可以通过拆分分支以使分支条件中仅提及一种类型,来解决此问题。