Kotlin:多种类型的智能转换

标签 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) s 然后使用一些“聪明的技巧”来选择正确的,但我宁愿不这样做。 ;)

最佳答案

智能转换不起作用,因为 when 分支中的代码 is B, is C -> map(it)只进行一次类型检查。它不会被编译成两组不同的指令,一种类型和另一种类型。编译器需要推断 it 的单一类型这在这两种情况下都有效。
Sub0 都不是和 Sub1可以选择 it 的类型,因为选择其中一个不会覆盖另一个。所以编译器选择Sub0的最不常见的父类(super class)型。和 Sub1 ,即 Super .然后调用map使用静态已知类型 Super 解析对于 it .

因此,确实,拆分分支以便在分支条件中仅提及一种类型是您可以解决此问题的方法。

关于Kotlin:多种类型的智能转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55687420/

相关文章:

reflection - 我可以在纯 Kotlin 中通过类名实例化一个对象吗

android - Firebase Crashlytics 使用 Retrofit 和协程报告 Android 项目上的假崩溃

java - 如何从 Javalin 读取多个主体参数?

android - 监听器绑定(bind);找不到二传手

hibernate - Kotlin 与 JPA/Hibernate : no lazy-loading without `open` ?

android - 为什么我不能在内部类 ViewHolder 中使用 var mSelectedItem?

android - 如何修复错误 : No signature of method: build_ap86oam3dut3pxce3x49rdtma. android()?

dictionary - 为什么类 'get' 的 'Map' 方法允许发送不相关的 key 而没有编译错误?

android - 如何在 LaunchedEffect 中使用 LocalContext?

java - 在可绘制对象中使用 ?attr/color 时出现滑动错误