2016-09-04 2 views
5

Kotlin provides “semicolon inference”: syntactically, subsentences (e.g., statements, declarations etc) are separated by the pseudo-token SEMI, which stands for “semicolon or newline”. In most cases, there’s no need for semicolons in Kotlin code.Kotlin의 세미콜론 유추 규칙은 무엇입니까?

이것은 grammar 페이지의 내용입니다. 이것은 어떤 경우에는 세미콜론을 지정할 필요가 있음을 암시하는 것으로 보이지만, 아래에 나와있는 문법 트리가이를 분명히하지는 않습니다. 또한이 기능이 제대로 작동하지 않아 문제가 발생할 수있는 경우가 있다는 의혹이 있습니다.

따라서 세미콜론을 삽입해야 할 때와 오류 코드 작성을 피하기 위해 알아야 할 코너 케이스는 무엇입니까?

+0

@JaysonMinard 저는 JavaScript의 전문가는 아니지만, 괜찮은 것처럼 보이지만 실제로 올바르게 작동하지 않는 언어 구조가 있다는 것을 알고 있습니다. 그리고 그 문제는 프로그램에서 버그를 발견 할 때까지는 문제가 있다는 것을 알지 못한다는 것입니다. 실수로 실수를 한 후에 곧 발생할 수도 있고 그렇지 않을 수도 있습니다. 나는 JavaScript의 문제있는 표현이 거의 없거나 거의 없다는 것을 확신하지만, 그렇다고해서 Kotlin이 그와 같은 까다로운 사례를 가지고 있지 않다는 것을 의미하지는 않습니다. 그리고 내가 무엇인지 알고 있다면 나는 물어볼 필요가 없다. 그것이 문제 다. – Malcolm

답변

14

컴파일러가 모호한 경우에만 세미콜론을 지정하면되고 세미콜론이 없으면 명백한 컴파일러 오류가 발생합니다.

규칙은 다음과 같습니다. 걱정하지 마십시오. 세미콜론을 사용하지 마십시오 (아래의 두 경우 제외). 컴파일러는 오류가 발생할 때 알려줍니다. 실수로 추가 세미콜론을 추가하더라도 구문 강조 표시는 "중복 된 세미콜론"이라는 경고와 함께 불필요하다는 것을 보여줍니다.

세미콜론의 일반적인 두 가지 경우 : 예

열거에 열거하며 성질 또는 기능의 목록이 열거 클래스 ENUM리스트 후 ; 필요 :

enum class Things { 
    ONE, TWO; 

    fun isOne(): Boolean = this == ONE 
} 

그리고 당신은 제대로 수행하지 않을 경우이 경우 컴파일러는 바로 당신을 말할 것이다 :

Error:(y, x) Kotlin: Expecting ';' after the last enum entry or '}' to close enum class body

세미콜론의

myThingMap.forEach { val (key, value) = it; println("mapped $key to $value") } 

부재를 마지막 예제에서 당신에게에서 더 신비 오류를 줄 것이다 : 당신은 어쩌면 간결을 위해, 같은 줄에 두 문장을 수행 할 때

그렇지 않으면 유일한 다른 일반적인 경우입니다 당신이하고있는 일이 혼란 스러울 때 가리 킵니다. 세 미 콜론이 제거되고 하나가 될 때 유효한 세미콜론으로 분리 된 두 개의 명령문으로 유효한 두 가지 코드를 작성하는 것은 정말로 어렵습니다.

이전에는 Kotlin 1.0 이상이 더 명확 해지기 때문에 더 이상 세미콜론이 필요하지 않게 된 후에 "익명"인 { ... }의 초기화 블록과 같은 다른 경우가있었습니다. 이러한 사례는 더 이상 언어에 남아 있지 않습니다. 이 기능의

신뢰 :

Also I have suspicions that there are some cases where this feature may not work correctly and cause problems.

이 기능은 증거가 어디 알려진 경우를 설정하지 않은이 기능 문제 및 코 틀린의 다년간의 경험이 있다는 것을이 없습니다, 잘 작동이 기능 역화. 누락 된 ;에 문제가 있으면 컴파일러에서 오류를보고합니다.

내 모든 오픈 소스 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 ()->Unit 유형의 함수 whatever("message") { doNothing() } 호출의 결과에 할당되고,이 경우; 세미콜론을 추가하면 함수 { doNothing() }이 지정되며 이는 ()->Unit입니다. 그래서 코드는 두 가지 모두 유효합니다. 그러나 모든 것이 완벽하게 일렬로 배열되어 있기 때문에 자연스럽게 이런 일이 발생하지는 않습니다.. feature suggested emit keyword or ^ hat operator은이 사건을 불가능하게 만들었을 것이며, 강력하게 제기 된 의견과 시간 제약으로 인해 1.0보다 먼저 고려되었습니다.

6

나는 Jayson Minard의 답변에 덧붙여, 세미콜론이 필요한 또 다른 이상한 경우를 경험했다. return 문을 사용하지 않고 함수를 반환하는 명령문 블록에 있으면 세미콜론이 필요합니다. 예를 들어 : 세미콜론없이

val doStuff:() -> Unit = when(x) { 
    is String -> { 
     { doStuff(x) } 
    } 
    else -> { 
     println("This is the alternate"); // Semicolon needed here 
     { doNothing() } 
    } 
} 

, 코 틀린는 { doNothing() }println()에 두 번째 인수하고 컴파일러가 오류를보고 생각한다.

+0

이 경우 컴파일러는 String 및 함수 인수를 모두 사용하는 println 버전을 찾을 수 없다는 오류를 표시하지만 표시된 행이 마지막 인수로 함수를 가져온 함수 함수를 호출하는 호출 작업이 있었지만 현재 허용되는 코드이므로 오류가 표시되지 않습니다. –

+2

고마워, 내가 정확히 찾고 있던 오류 유형이야!그래서 나는 누군가가 추론이 항상 올바로 작동한다고 말할 때 대개 매우 신중합니다. Jayson Minard는 JavaScript에 대한 언급에 너무 얽매여있는 것처럼 보입니다.이 점은 Kotlin에서 유사한 문제가 얼마나 적게 발생했는지 보여주는 좋은 예입니다. – Malcolm

+1

@Malcolm 다른 점은 Kotlin이 다른 경우와 마찬가지로이 경우 컴파일 타임 오류를 줄 것입니다. 코드가 실행되고 예기치 않은 동작이 발생하는 것은 아닙니다. 이 경우는 람다가 마지막 매개 변수로 받아 들여지면';'을 사용하거나 사용하지 않는 유효한 구문이므로 컴파일은 모호한 상황을 포착하고 오류를 발생시킵니다. 그것은 위험하지 않습니다. 그리고 그것은 Kotlin에서';'을 추측함으로써 위험을 초래하지 않는다는 점에서 javascript와 비교하여 지적하고 싶습니다. –

5

코 틀린은 대부분이으로 추측됩니다. 예외가있는 것처럼 보입니다 (Jayson Minard의 enum 예 참조).

일반적으로 형식 시스템은 유추 된 세미콜론을 잘못 인식하지만 컴파일러가 실패하는 경우가 있습니다.

호출의 인수 (괄호 포함) 다음 줄에있는 경우, 코 틀린 인수는 단순히 새로운 괄호에 표현 문이 있다고 가정합니다 :

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()는 않을 것 한 줄에 딱 맞는다. 즉, 개발자는 단순히 함수에 대한 호출을 별도의 줄에 작성해야합니다.