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
的 's 会变得很长:
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
,因为选择其中一个不会覆盖另一个。所以编译器选择 and 的最不常见的超类型Sub0
,Sub1
即Super
. map
然后使用静态已知类型解析Super
对的调用it
。
因此,确实,拆分分支以便在分支条件中仅提及一种类型是您可以解决此问题的方法。
推荐阅读
- c++ - 算术表达式的显式(long long)转换返回 0
- javascript - 登录后Testcafe测试崩溃(企业网站重定向失败)
- android - 应该使用哪个回调来检测从屏幕上删除的 android 片段并且它不再可见
- sharepoint - 将大文件上传到 SharePoint 引发错误(System.Net.WebException:请求已中止:请求已取消。)
- javascript - Javascript 复选框显示错误
- swift - 在 Swift 中比较日期忽略当前时区
- java - org.apache.http.ContentTooLongException:实体内容太长 [105539255] 对于配置的缓冲区限制 [104857600]
- javascript - 如何删除从数组中选择的元素
- php - 如何显示我的 html 邮件?
- ios - 找到不支持的类型 - AVMetadataObject