본문 바로가기
Kotlin/Release Notes

[Kotlin Release Notes] Kotlin M12 is out!

by 노력남자 2023. 8. 28.
반응형

2015년 5월 29일

 

Kotlin M12를 소개합니다. 이 버전은 중요한 변경 사항과 새로운 기능을 가져왔습니다:

- 주석 및 열거형을 위한 새로운 구문

 

- 함수 타입의 편리한 의미론

 

- 더 나은 스마트 캐스트

 

- Java 주석 처리 지원을 위한 kapt

 

- 여러 IDE 기능 등

 

언어


언어 및 핵심 라이브러리에 도입된 변경 사항 중 많은 부분은 더 이상 권장하지 않는 것입니다. "코드 정리..." 동작을 사용하여 프로젝트에서 경고를 자동으로 수정할 수 있습니다.


주석: 새로운 구문


이전에 언급했듯이 대괄호 []를 좀 더 생산적인 미래 사용을 위해 예약하고 주석 구문을 Java 사용자에게 더 익숙한 형태로 만들기로 결정했습니다. 따라서 M12부터 [Foo(args)] 대신 @Foo(args) 형식으로 작성합니다. 더 자세한 내용은 여기(더 자세한 내용은 사양 문서에서 확인할 수 있음)에서 확인할 수 있습니다.

@는 대부분의 경우에 필요하지 않습니다. 보통 우리는 다음과 같이 어떠한 이스케이프도 사용하지 않고 주석을 작성합니다:

 

data class Foo // `data`는 주석입니다

 

[...]를 기반으로 한 이전 구문은 폐기되었으므로 컴파일러는 코드에서 경고를 발생시킬 것입니다. 이러한 경고를 수정하려면 Alt+Enter를 누르고 빠른 수정(개별 또는 전체 프로젝트에 대해)을 실행하세요. 앞서 언급한 "코드 정리..." 동작도 전체 프로젝트에 대해 작동합니다.

 

라벨 구문 변경


M12부터 @name은 주석입니다. 그러나 이전에 의미가 있었습니다. 즉, 라벨이었습니다. 라벨을 위한 다른 구문을 찾아야 했으며, 이제 라벨은 끝에 @를 붙여서 선언합니다:

 

loop@ for (i in 1..100) {
  for (j in 1..100) {
    if (...)
      break@loop
  }
}

 

따라서 loop@는 라벨을 선언하고, break@loop는 그것을 사용합니다.

 

클래스 리터럴과 주석


이전 M12 버전에서는 Kotlin 주석 내에서 java.lang.Class를 사용할 수 있었습니다. 예를 들어:

 

annotation class handledBy(val handlerClass: Class<out Handler>)
// 사용법
handledBy(javaClass<MyHandler>())
class MyEvent {...}

 

그러나 이제 Kotlin 주석 내에서 Java 특정 클래스를 사용하는 것은 폐기되었으며, 대신 Kotlin의 모델인 kotlin.reflect.KClass를 사용해야 합니다. java.lang.Class 대신에 kotlin.reflect.KClass를 사용하고, javaClass<Foo>() 대신에 Foo::class를 사용해야 합니다:

 

annotation class handledBy(val handlerClass: KClass<out Handler>)
// 사용법
handledBy(MyHandler::class)
class MyEvent {...}

 

Java 주석을 Kotlin에서 처리할 때는 java.lang.Class 대신 KClass로 해석됩니다:

 

// Java
@interface JavaAnnotation {
    Class<?> value();
}
// Kotlin
fun introspect(jann: JavaAnnotation) {
    val theClass = jann.value // 이 식의 유형은 KClass<*>
    ...
}

 

이제 KClass를 java.lang.Class로 변환해야 할 때는 .java를 호출하여 변환할 수 있습니다. 예를 들어 Foo::class.java 또는 jann.value.java와 같이 사용할 수 있습니다.

 

주석이 있는 기본 생성자


기본 생성자 구문을 더 규칙적으로 만들기로 결정하였으며, 이제 기본 생성자의 전체 형식에는 constructor 키워드가 포함됩니다:

class PrivateConstructor private constructor (val x: Int) {
    ...
}

 

전체 형식은 주로 주석을 달거나 수정자를 추가할 때 필요합니다. 대부분의 경우 이전 익숙한 구문이 여전히 작동합니다:

 

class MyClass(val x: Int) {
    ...
}

 

트레이트는 이제 인터페이스입니다


트레이트가 어차피 제한적이며 Java의 인터페이스와 거의 동일하기 때문에, trait 키워드를 폐기하고 대신 interface를 사용하도록 결정했습니다. 예상대로 빠른 수정과 "코드 정리..."를 통해 도움을 받을 수 있습니다.

 

열거형 클래스: 새로운 구문


새로운 열거형 구문은 Java의 구문과 매우 유사합니다. 이제 열거형 항목은 쉼표로 구분되어야 합니다:

 

enum class Foo {
    A, B, C
}

 

이제 열거형 클래스의 멤버를 선언할 때 모든 항목 뒤에 있어야 하며, 마지막 항목 뒤에는 세미콜론이 있어야 합니다:

enum class FooWithMember {
    FOO,
    BAR,
    BAZ;
    fun doIt() { ... }
}

 

마지막으로, 열거형이 생성자를 가진 경우, 인수를 항목 이름 옆에 바로 전달하여 호출할 수 있습니다:

 

enum class Color(val rgb: Int) {
  RED(0xFF0000),
  GREEN(0x00FF00),
  BLUE(0x0000FF)
  // 멤버 없음 => 세미콜론은 여기에서 필요하지 않습니다.
}

 

이전 구문은 폐기되었습니다.

 

함수 타입 개편


함수 타입과 확장 함수 타입을 통합하여 이제 종종 상호 교환하여 사용할 수 있습니다. 예를 들어 함수 '(String) -> Int'가 기대되는 곳에 String::length를 전달할 수 있습니다.

 

// map()은 `(String) -> Int`를 기대합니다
// 인수의 유형은 `String.() -> Int`입니다
strings.map(String::length)

 

자세한 건 여기 참고

 

만약 Java 코드에서 Kotlin의 함수 클래스(kotlin.Function1 등)를 사용했다면, 이제 이러한 클래스들은 kotlin.jvm.functions 패키지에 위치해 있으므로 조정해야 합니다. "Java에서 사용된 기능 클래스의 사용" 검사를 사용하여 모든 Java 코드를 마이그레이션할 수 있습니다.

 

스마트 캐스트가 더욱 똑똑해졌습니다


오래 기다렸던 기능: 이제 Kotlin은 로컬 var에 대한 스마트 캐스트를 수행할 수 있습니다:

 

var foo = bar()
if (foo != null) {
    foo.baz() // 이곳에서 오류가 발생하지 않습니다.
}

 

물론, 스마트 캐스트는 컴파일러가 관련한 확인이 수행된 후에 수정이 발생하지 않았다는 것을 알 때만 작동합니다. 루프는 종종 이러한 상황을 왜곡시키므로 (스마트 캐스트에 완전한 데이터 흐름 분석을 사용할 수 없기 때문에) 루프에서 var이 변조된 경우 스마트 캐스트가 작동하지 않을 수 있습니다.

동일한 모듈에서의 공개 및 보호되는 불변 val에 대한 스마트 캐스트도 이제 가능합니다:

 

class C(public val d: D?)
fun foo(c: C) {
    if (c.d != null) {
        c.d.foo() // 여기에서 c.d가 스마트 캐스트됨
    }
}

 

인라이닝 및 비로컬 반환을 위한 함수 표현식 지원


M11에서 소개된 함수 표현식은 이제 인라인 호출에서 지원됩니다:

 

fun test(list: List<Foo?>) {
    val mapped = list.map(fun (item) = item?.toString() ?: return@test) // 비로컬 반환
    ...
}

 

폐기 및 중지된 기능


M12에서는 이전에 폐기된 기능 몇 가지가 제거되었습니다:

- class object가 companion object를 대신하도록 삭제되었습니다.

 

- init은 이제 익명 초기화 블록 앞에 필수적입니다.


일부 기능이 폐기되었습니다:

- when에서의 break 및 continue


- 클래스를 확장하는 인터페이스


- 공변적인 상위 유형 특화


- 정적 유형 assertions


빠른 수정과 "코드 정리..."를 사용하여 프로그램을 마이그레이션하세요.

 

Java 상호 운용성


jvmOverloads


Kotlin은 기본 인자를 사용하여 오버로드에 대한 필요성을 크게 줄였지만, Java 클라이언트는 이 기능을 직접 활용할 수 없습니다.
M12에서는 Kotlin 함수에 N개의 기본 매개변수가 있는 경우 컴파일러가 N+1개의 오버로드를 생성하도록 알려주는 jvmOverloads 주석을 추가했습니다.
예를 들어,

 

jvmOverloads fun f(a: String, b: Int = 0, c: String = "abc") {
    ...
}

 

다음과 같은 오버로드가 생성됩니다.

// Java
void f(String a, int b, String c)
void f(String a, int b)
void f(String a)


더 나은 디버깅을 위한 소스 맵 (JSR-45)


이제 생성된 클래스 파일에 컴파일러가 생성한 소스 맵 테이블로 인해 인라인된 함수의 본문을 따라갈 수 있습니다.

일부 기술적인 참고 사항: 각 클래스 파일에는 명령에 할당된 줄 번호가 있습니다. 인라인된 함수 본문에는 실제 파일 끝 이후의 줄 번호를 할당하며 (예: 파일이 50개의 줄을 가진 경우 인라인된 코드는 51부터 시작하는 줄 번호를 가짐), 이러한 "가상" 번호는 가능한 다른 파일에 있는 인라인된 코드의 실제 소스에 매핑됩니다. 표준 JVM 디버거는 소스 매핑을 이해하고 해당 파일과 줄을 따라갈 수 있습니다. 유일한 주의점은 가끔 예외 스택 추적이 파일 끝 이후의 줄 번호를 포함할 수 있다는 점입니다. 이 문제에 대한 해결책을 찾고 있습니다.

 

Java 주석: 인자 순서


Java에서 주석은 인터페이스이며 해당 인터페이스의 매개변수는 해당 인터페이스의 메서드입니다. 따라서 매개변수의 순서는 중요하지 않으며 호출 사이트는 이에 의존할 수 없습니다. 이것이 Java에서 모든 인자 중 하나 (value라는 이름)를 제외한 모든 인자를 이름으로 전달해야 하는 이유입니다.

Kotlin에서 선언된 주석은 명명된 매개변수 및 가변 인자를 허용하는 올바른 생성자를 갖추고 있지만, Java 주석에서는 이러한 측면에서 신뢰할 수 없으므로 이제 다음 내용이 Java 주석에 적용됩니다.

- 오직 value라는 이름의 매개변수만 이름 없이 전달할 수 있습니다.


- 오직 value라는 이름의 매개변수만 가변 인자일 수 있으며 (Java에서 배열인 경우 자동으로 가변 인자가 됨),


- 다른 모든 매개변수는 위치로 전달할 수 없습니다.

 

JavaScript


JavaScript 백엔드도 JVM 백엔드에 따라잡고 있습니다. M12에서 다음을 지원합니다:

- 모듈 간 인라인


- reified 매개변수


- 함수 표현식


- 보조 생성자

 

도구


kapt: 주석 처리 (JSR-269)


이 게시물에서 언급한 대로, M12에서는 Dagger 2와 같은 프레임워크가 Kotlin과 함께 작동하도록 주석 처리에 대한 초기 지원이 추가되었습니다. 현재 구현의 주요 제한은 Kotlin 코드가 주석 처리기에 의해 생성된 어떠한 선언에도 참조할 수 없다는 것입니다 (따라서 Dagger의 경우 Java로 적어도 하나의 작은 클래스를 작성해야 합니다).

우리는 Kotlin 컴파일러에 의해 생성된 클래스에 대한 스텁을 생성하여 이 제한을 나중에 해결할 계획입니다. 자세한 내용은 앞서 언급한 게시물에서 확인하십시오.


Gradle: 안드로이드용 JUnit 지원


Kotlin Gradle 플러그인은 이제 안드로이드용 JUnit 테스트를 지원합니다. 우리가 해야 할 일은 Java의 표준 절차를 따르는 것이지만 이제 Kotlin으로 테스트를 작성할 수 있습니다.


Quasar 지원


Kotlin의 최근 변경 사항 중 일부는 생태계에 훌륭한 추가 기능을 제공했습니다: 이제 Quasar는 Kotlin을 위한 fibers(가벼운 스레드), Go와 유사한 채널, Erlang과 유사한 액터 등 다양한 비동기 도구를 제공합니다! 발표 내용은 여기에서 확인하십시오.


표준 API 변경


M12는 표준 라이브러리에 새로운 기능을 추가했습니다:

- kotlin.io 패키지의 새로운 유틸리티


- 새로운 텍스트 유틸리티

 

- JVM 및 JS를 통합한 정규 표현식 API

 

- 새로운 컬렉션 유틸리티

 

- JVM 및 JS 모두에 대해 모든 숫자 형식에 대해 MIN_VALUE 및 MAX_VALUE 사용 가능

 

Kotlin 표준 라이브러리를 개선하면서 몇 가지 내용이 변경되거나 폐기됩니다. 코드 마이그레이션을 위해 빠른 수정 및 "코드 정리..." 동작을 사용하십시오. (표준 라이브러리의 소스를 프로젝트에 연결했는지 확인해주세요.)

전체 변경 내용 목록은 여기에서 확인하실 수 있습니다.

 

IntelliJ IDEA 플러그인


Kotlin IDE는 이제 선택한 함수 내부에서 표현식을 매개 변수로 변환하는 표준 Introduce Parameter 리팩터링을 지원합니다:

 

 

게다가, Introduce Lambda Parameter도 사용 가능하여 코드 일부를 함수 값으로 추출할 수 있습니다:

 

 

Rename에는 관련된 선언 (변수, 하위 클래스 등)의 이름을 변경하는 옵션이 있습니다:

 

 

우리는 최근 많은 폐기사항을 추가하고 있기 때문에, IDE는 이제 ReplaceWith 퀵 픽스를 지원합니다: 폐기된 호출을 대체할 식을 폐기된 주석의 (선택적) 추가 매개 변수에 지정할 수 있습니다:

 

 

사용자의 폐기된 선언에 ReplaceWith를 추가하는 의도 작업이 있습니다.

 

그 외의 변경 사항:

- 새로운 디버거 기능


1. 로컬 함수에 대한 표현식 평가

 

2. 필드 워치 포인트 (백킹 필드가 있는 속성에만 해당)

 

- 패키지 변경 의도 작업

 

- 함수의 종료 지점 강조

 

- 재귀 호출을 위한 풋터 마크

 

- 사용되지 않는 수신자 매개 변수 검사

 

- 가져오기에 대한 코드 스타일 설정 (예: 특정 패키지를 항상 '*'와 함께 가져올 수 있습니다)

 

- Java2Kotlin 변환기는 이제 다른 파일의 사용도 업데이트하도록 제안합니다

 

- 완료 목록이 열려 있는 상태에서 '!'를 입력하면 부정 호출이 삽입됩니다 (예: !foo.isEmpty())

 

- 가시성 수정자를 변경하는 의도 작업

 

- 이제 의도 작업의 사용 가능 범위가 훨씬 개선되었습니다

 

- 슈퍼클래스의 생성자에 매개 변수가 있는 경우 베이스 클래스에서 매개 변수를 추가하는 빠른 수정

 

아직 구현되지 않은 내용들


우리는 여전히 이전에 발표한 일부 변경 사항에 대해 작업 중입니다, 예를 들어 Java에 대한 추가적인 Null-안전성입니다. 준비가 완료되는 대로 배포될 것입니다.

 

추가 발표 예정


가장 가까운 미래에 M12와 관련된 더 많은 자료가 게시될 예정입니다. 기대해 주세요!

 

원문

 

https://blog.jetbrains.com/kotlin/2015/05/kotlin-m12-is-out/

반응형

댓글