位置:首页 > Scala > Kotlin中val定义ArrayList初始化报错原因与解决方法

Kotlin中val定义ArrayList初始化报错原因与解决方法

时间:2026-08-15  |  作者:半糖攻略君  |  阅读:0

1 语法错误?

也许看了我们的题目,大家还没有明白过来到底发生了什么,那么我请大家再仔细看看:

  1. val list: ArrayList<String>= ArrayList()

  2. ^

什么地方报错呢?就是泛型参数后面的 > 处。

这就让人不理解了,看上去并没有什么问题啊。我们再来看看错误提示:

Kotlin中val定义ArrayList初始化报错原因与解决方法_wishdown.com

嗯?说 > 那个地方缺个 > ? 什么鬼。。好吧,我大概猜到原因了,泛型参数后半个 > 估计与后面赋值用的 = 连起来被识别成了 >=,于是乎。。。

Kotlin中val定义ArrayList初始化报错原因与解决方法_wishdown.com

我们打开 PsiViewer(IntelliJ 插件),将光标放到报错的位置,嗯,这货果然被识别成了 >= (GTEQ)。

2 分析 Kotlin 的解析过程

说到这里,事情就有点意思了:Kotlin 的解析器并不会因为前面出现了泛型,就把后面的 >= 认成 > =这是不是意味着,解析时会先由词法分析器把连续字符切分、识别成一个个 TOKEN,再交给语法分析器基于这些 TOKEN 去判断并还原具体语法?

想要验证这个其实并不难,我们找到 Kotlin 的源码,找到 lexer 相关的源码:

Kotlin中val定义ArrayList初始化报错原因与解决方法_wishdown.com

在 Kotlin.flex 这个文件中发现:

  1. ">=" { return KtTokens.GTEQ ; }

不惊讶吧。实际上编译之后 Kotlin.flex 会生成 _JetLexer.ja va 这个文件,KotlinLexer 这个类是词法分析器的入口,我们在解析处打个断点:

Kotlin中val定义ArrayList初始化报错原因与解决方法_wishdown.com

注意 FlexAdapter 实际上是 KotlinLexer 的父类。

调试运行编译器,我比较喜欢的方式是编译一段脚本:

Kotlin中val定义ArrayList初始化报错原因与解决方法_wishdown.com

脚本里面就只有我们最开头的那句报错的代码,那么结果会怎样呢?

Kotlin中val定义ArrayList初始化报错原因与解决方法_wishdown.com

我们看下调用堆栈,解析器被调用的地方实际上是 PsiElement 构造的过程中。我们再来看看 doParseContents 这个方法是干什么的:

Kotlin中val定义ArrayList初始化报错原因与解决方法_wishdown.com

一旦 PsiElement 构造完成,那么词法分析实际上就结束了,后面的 KotlinParser 就是语法分析了。这样看起来似乎跟我们前面猜测的没有什么两样。

Kotlin中val定义ArrayList初始化报错原因与解决方法_wishdown.com

显然在语法分析之前,这俩符号已经被强制结合成 >=,后面也并没有做重新解析的操作。

3 对比看看其他语言

能够出现类似语法的,我们可以对照一下 Swfit 和 Scala。

先说说 Scala,它的解析器应该是极其强大的,毕竟人家允许各种字符作为运算符啊。。

Kotlin中val定义ArrayList初始化报错原因与解决方法_wishdown.com

嗯,毕竟人家的泛型参数机智地选择了 [] 而不是 <> ,OK,你赢了。。

那么我们再来看看 Swift 吧,这个比较有说服力:

  1. let ints: Array<Int>= [1, 2, 4]

  2. ints.forEach{item in print(item)}

Kotlin中val定义ArrayList初始化报错原因与解决方法_wishdown.com

瞧见没,人家就能识别出来!当然这里有个奇怪的地方,如果你用 JetBrains 家的 AppCode 运行这段代码,结果就会报错,额,这也许是一个悲伤的故事。。

4 一些思考

实际上通过前面的讨论,我们就知道为什么 Kotlin 的移位居然不用 >><<,而是 shrshr 这样的中缀表达式,毕竟人家没办法识别呀。。

好啦,其实这都不是什么大问题了,这篇文章探讨的那句代码本身就比较蛋疼:

  1. val list: ArrayList<String>= ArrayList()

我就问你为什么不去掉前面的类型,类型推导难道还不够吗?

  1. val list = ArrayList<String>()

或者在 >= 中间打一个空格嘛,这样就啥事儿没有了。

而说到移位用中缀表达式的问题,我们群里有位大佬就终于忍不住为 Kotlin 发声了:

用中缀这种方法未尝不好啊。因为其实位移这种根本没什么人用的,直接换成一个方法其实在概念理解上简单多了。

还有一点挺有意思,Scala 用[ ]来表示泛型,读起来、看起来都比<>顺手不少。之前也见过有人提到,后者写起来多少有点“反人类”,或者至少视觉上显得别扭,这个判断确实很容易让人共鸣。不过话说回来,像>=这类情况如果编译器一时解析不好,其实也算不上什么大问题,很多语言里都多少有类似的小缺陷,但通常并不会真正构成障碍。


欢迎关注微信公众号 Kotlin

Kotlin中val定义ArrayList初始化报错原因与解决方法_wishdown.com

《夸克》非常好用的免费AI浏览器

下载APP查看

免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多