Kotlin обеспечивает «вывод точки с запятой»: синтаксически субпредложения (например, утверждения, объявления и т. Д.) Разделяются псевдо-токеном SEMI, что означает «точка с запятой или новая строка». В большинстве случаев точка с запятой в коде Kotlin не нужна.
Об этом говорится на странице грамматики. Похоже, это подразумевает, что в некоторых случаях необходимо указывать точки с запятой, но они не указываются, и дерево грамматики ниже не делает это очевидным. Также у меня есть подозрения, что в некоторых случаях эта функция может работать некорректно и вызывать проблемы.
Итак, вопрос в том, когда следует вставлять точку с запятой и какие угловые случаи нужно знать, чтобы избежать написания ошибочного кода?
3 ответа
Вам нужно указывать точку с запятой только в тех случаях, когда компилятору неясно, что вы пытаетесь сделать, а отсутствие точки с запятой приведет к очевидной ошибке компилятора.
Правило: не беспокойтесь об этом и вообще не используйте точки с запятой (кроме двух случаев, указанных ниже). Компилятор обязательно сообщит вам, когда вы ошиблись. Даже если вы случайно добавите дополнительную точку с запятой, подсветка синтаксиса покажет вам, что в этом нет необходимости, с предупреждением о «избыточной точке с запятой».
Два распространенных случая использования точки с запятой:
Класс перечисления, который имеет список перечислений, а также свойства или функции в перечислении, требует ;
после списка перечислений, например:
enum class Things {
ONE, TWO;
fun isOne(): Boolean = this == ONE
}
И в этом случае компилятор скажет вам напрямую, если вы не сделаете это правильно:
Ошибка: (y, x) Котлин: Ожидается ';' после последней записи перечисления или '}', чтобы закрыть тело класса перечисления
В противном случае единственный другой распространенный случай - это когда вы выполняете два оператора в одной строке, возможно, для краткости:
myThingMap.forEach { val (key, value) = it; println("mapped $key to $value") }
Отсутствие точки с запятой в этом последнем примере приведет к более загадочной ошибке в том месте, где вы запутаетесь в том, что вы делаете. Действительно сложно создать код, который был бы действительным как два оператора, разделенные точкой с запятой, которые также действительны, когда точка с запятой удаляется и они становятся одним целым.
В прошлом были и другие случаи, такие как блок инициализации класса, который был более «анонимным» { ... }
до Kotlin 1.0, а позже стал init { ... }
, который больше не нуждался в точке с запятой, потому что он намного понятнее. Эти случаи больше не остаются в языке.
Уверенность в этой функции:
Также у меня есть подозрения, что в некоторых случаях эта функция может работать некорректно и вызывать проблемы.
Эта функция работает хорошо, нигде нет доказательств того, что с этой функцией есть проблемы, а годы опыта Kotlin не выявили никаких известных случаев, когда эта функция имела бы обратный эффект. Если есть проблема с отсутствующим ;
, компилятор сообщит об ошибке.
Обыскивая весь мой Kotlin с открытым исходным кодом и наши внутренние довольно большие проекты Kotlin, я не нашел точек с запятой, кроме случаев, указанных выше - и их очень и очень мало. Как правило, поддерживая идею «не использовать точки с запятой в Kotlin».
Однако возможно, что вы можете намеренно придумать случай, когда компилятор не сообщает об ошибке, потому что вы создали код, который действителен и имеет различное значение с точкой с запятой и без нее. Это будет выглядеть следующим образом (измененная версия ответа @Ruckus):
fun whatever(msg: String, optionalFun: ()->Unit = {}): () -> Unit = ...
val doStuff: () -> Unit = when(x) {
is String -> {
{ doStuff(x) }
}
else -> {
whatever("message") // absence or presence of semicolon changes behavior
{ doNothing() }
}
}
В этом случае doStuff присваивается результат вызова whatever("message") { doNothing() }
, который является функцией типа ()->Unit
; и если вы добавите точку с запятой, ей будет назначена функция { doNothing() }
, которая также имеет тип ()->Unit
. Так что код действителен в обоих направлениях. Но я не видел, чтобы что-то подобное происходило естественным образом , поскольку все должно быть идеально согласовано. предложенная функция emit
ключевого слова или ^
оператора шляпы будет иметь сделали этот случай невозможным, и он был рассмотрен, но отклонен до версии 1.0 из-за резко противоположных мнений и ограничений по времени.
В дополнение к ответу Джейсона Минарда я столкнулся с еще одним странным крайним случаем, когда требуется точка с запятой. Если вы находитесь в блоке операторов, который возвращает функцию без использования оператора return, вам понадобится точка с запятой. Например:
val doStuff: () -> Unit = when(x) {
is String -> {
{ doStuff(x) }
}
else -> {
println("This is the alternate"); // Semicolon needed here
{ doNothing() }
}
}
Без точки с запятой Котлин считает, что оператор { doNothing() }
является вторым аргументом для println()
, и компилятор сообщает об ошибке.
Kotlin, кажется, в основном с нетерпением вводит точки с запятой. Кажется, есть исключения (как показано в примере перечисления Джейсона Минарда).
Обычно система типов улавливает неверно выведенные точки с запятой, но есть несколько случаев, когда компилятор дает сбой.
Если аргументы вызова находятся в следующей строке (включая круглые скобки), Kotlin будет считать, что аргументы - это просто новый оператор выражения в скобках:
fun returnFun() : (x: Int) -> Unit {
println("foo")
return { x -> println(x) }
}
fun main(args: Array<String>) {
println("Hello, world!")
returnFun()
(1 + 2) // The returned function is not called.
}
Более распространенным случаем может быть следующий, когда у нас есть возврат с выражением в следующей строке. В большинстве случаев система типов будет жаловаться на отсутствие возвращаемого значения, но если тип возврата - Unit
, то все ставки отключены:
fun voidFun() : Unit {
println("void")
}
fun foo() : Unit {
if (1 == 1) return
voidFun() // Not called.
}
fun bar() : Unit {
if (1 == 1)
return
voidFun() // Not called.
}
Функция bar
потенциально может сработать, если return voidFun()
не поместится на одной строке. Тем не менее, разработчики должны просто написать вызов функции в отдельной строке.
Похожие вопросы
Связанные вопросы
Новые вопросы
kotlin
Kotlin — это язык программирования высокого уровня, разработанный JetBrains. Используйте этот тег, если у вас возникли проблемы с языком Kotlin и стандартной библиотекой. Этот тег часто используется вместе с дополнительными тегами для различных целей (JVM, JavaScript, нативные и т. д.) и библиотек/фреймворков (Android, Spring и т. д.), используемых разработчиками Kotlin, если вопрос относится именно к этим темам.