在java中我们使用分号,编译器在分号的基础上理解语句的结尾。
而Kotlin
也使用 JVM 编译器如何理解这是没有分号的语句的结尾Kotlin
?
在java中我们使用分号,编译器在分号的基础上理解语句的结尾。
而Kotlin
也使用 JVM 编译器如何理解这是没有分号的语句的结尾Kotlin
?
补充答案
TruncatedSemanticWhitespaceAwarePsiBuilder
Kotlin词法分析器在基于换行符对纯文本代码进行标记方面足够聪明。
无需插入(或用分号替换它们)即可完成此换行识别。在这里查看讨论
SemanticWhitespaceAwarePsiBuilderImpl
是这个接口的一个实现,它有newlineBeforeCurrentToken()方法,它提供了一些关于它是如何工作的线索:
@Override
public boolean newlineBeforeCurrentToken() {
if (!newlinesEnabled.peek()) return false;
if (eof()) return true;
// TODO: maybe, memoize this somehow?
for (int i = 1; i <= getCurrentOffset(); i++) {
IElementType previousToken = rawLookup(-i);
if (previousToken == KtTokens.BLOCK_COMMENT
|| previousToken == KtTokens.DOC_COMMENT
|| previousToken == KtTokens.EOL_COMMENT
|| previousToken == SHEBANG_COMMENT) {
continue;
}
if (previousToken != TokenType.WHITE_SPACE) {
break;
}
int previousTokenStart = rawTokenTypeStart(-i);
int previousTokenEnd = rawTokenTypeStart(-i + 1);
assert previousTokenStart >= 0;
assert previousTokenEnd < getOriginalText().length();
for (int j = previousTokenStart; j < previousTokenEnd; j++) {
if (getOriginalText().charAt(j) == '\n') {
return true;
}
}
}
return false;
}
每当需要检查令牌时都会调用它:
private boolean tokenMatches(IElementType token, IElementType expectation) {
if (token == expectation) return true;
if (expectation == EOL_OR_SEMICOLON) {
if (eof()) return true;
if (token == SEMICOLON) return true;
if (myBuilder.newlineBeforeCurrentToken()) return true;
}
return false;
}
因此,newlineBeforeCurrentToken()
逐个字符解析并与换行符进行比较,最终返回 true 表示它是一个完整的语句。
如此处所述,
在 Kotlin 中,分号是可选的,因此换行很重要。
这本质上意味着kotlinc
可以以与相同的方式识别语句的结尾javac
,唯一的区别是标记语句结尾的字符,其中javac
查找;
,kotlinc
将查找\n
(换行符)。
例如,如果省略分号,以下代码将无法编译
enum class Fruit(val price: Double) {
MANGO(100.0);
fun printPrice(){
print(price)
}
}
分号不会为代码添加任何对人类有价值的意义。生命太短暂,不能打扰他们。这只是 Java 中许多非必要复杂性示例中的一个(当然是次要的),这些示例已被更现代的 JVM 语言删除。
在 Kotlin 中,分号是可选的,但换行符很重要。
Kotlin 编译器通常会识别语句的结尾,即使没有显式 ; - 例如通过换行符。
重要 如果您想在一行中记录多个语句,它们之间用 ; 分隔。例如 :
val a = 42 ; println(a)