Kotlin:多种类型的智能投射

Fra*_*lik 3 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")
Run Code Online (Sandbox Code Playgroud)

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

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

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

Super
*Super
*Super
Run Code Online (Sandbox Code Playgroud)

这表明它选择了正确的路径,但没有进行自动广播。这种方法行得通,但随着您拥有越来越多的,它会变得很长SubX

when (it) {
    is Sub0 -> {
        print("*");
        map(it)
    }
    is Sub1 -> {
         print("*");
         map(it)
    }
    else -> map(it)
}
Run Code Online (Sandbox Code Playgroud)

我知道我可以以反射的形式使用一些黑魔法map(X),然后对所有s 进行迭代,然后使用一些“巧妙的技巧”来选择正确的选择,但是我宁愿不这样做。;)

hot*_*key 5

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

无论的Sub0Sub1可以选择的类型it,因为选择其中的一个不包括其他。所以编译器选择的最小公用超类型Sub0Sub1,这是Super。然后调用map与静态已知类型的解决Superit

因此,确实可以通过拆分分支以使分支条件中仅提及单个类型的方法来解决此问题。