코틀린 가이드의 번역내용입니다.
https://kotlinlang.org/docs/reference/whatsnew13.html
Contracts
Kotlin 컴파일러는 광범위한 정적 분석을 수행하여 경고를 제공하고 boilerplate code를 줄입니다. 가장 주목할만한 기능 중 하나는 스마트 캐스트입니다. 컴파일러의 type check 에 따라 자동으로 type 캐스트를 수행 할 수 있습니다.
fun foo(s: String?) {
if (s != null) s.length // Compiler automatically casts 's' to 'String'
}
하지만 type check 로직이 별도의 함수로 분리되면 smartcast 는 사라집니다.
fun String?.isNotNull(): Boolean = this != null // type check 로직 분리됨
fun foo(s: String?) {
if (s.isNotNull()) s.length // No smartcast :(
}
To improve the behavior in such cases, Kotlin 1.3 introduces experimental mechanism called contracts.
Contracts allow a function to explicitly describe its behavior in a way which is understood by the compiler. Currently, two wide classes of cases are supported:
Improving smartcasts analysis by declaring the relation between a function's call outcome and the passed arguments values:
이러한 동작을 개선하기 위해 Kotlin 1.3에는 Contracts 라는 experimental mechanism 이 도입되었습니다.
Contracts 는 함수가 컴파일러가 이해하는 방식으로 동작을 명시적으로 설명 할 수 있도록 합니다.
현재 두 가지 종류의 사례가 지원됩니다.
- 함수의 호출 결과와 전달 된 인수 값 사이의 관계를 선언하여 스마트 캐스트 분석을 개선합니다.
@ExperimentalContracts
fun requireWithContract(condition: Boolean) {
// 이 함수가 성공적으로 리턴되면 컴파일러에게 condition (함수)는 true 라는 것을 알려준다.
contract { returns() implies condition }
// condition 이 false 이면 exception 발생하므로 함수가 성공적으로 리턴되지 않는다.
if (!condition) throw IllegalArgumentException()
}
fun String?.requireWithFunction() = this != null
@ExperimentalContracts
fun foo(s: String?) {
if (s.requireWithFunction()) {
s.replace(" ", "") // String? 에 대한 null check error 발생, ? 또는 !! 필요
print(s)
}
requireWithContract(s is String)
s.replace(" ", "") //smart cast 되어 ? 필요없음
}
- kotlin-stdlib 에 적용된 예시
/**
* Returns `true` if this nullable collection is either null or empty.
* @sample samples.collections.Collections.Collections.collectionIsNullOrEmpty
*/
@SinceKotlin("1.3")
@kotlin.internal.InlineOnly
public inline fun <T> Collection<T>?.isNullOrEmpty(): Boolean {
// 이 함수가 false 를 반환하는 경우, this@isNullOrEmpty != null 임을 컴파일러에게 알려준다.
contract {
returns(false) implies (this@isNullOrEmpty != null)
}
return this == null || this.isEmpty()
}
fun abc() {
val abc: List<Int>? = null
abc.indexOf(0) // null type check 에러
if (abc.isNullOrEmpty()) {
abc.indexOf(0) // null type check 에러
}else{
abc.indexOf(0) // smart cast
}
}
- 고차 함수가있을 때 변수 초기화 분석 개선 (아직 적용 안해봄)
fun synchronize(lock: Any?, block: () -> Unit) {
// It tells compiler:
// "This function will invoke 'block' here and now, and exactly one time"
contract { callsInPlace(block, EXACTLY_ONCE) }
}
fun foo() {
val x: Int
synchronize(lock) {
x = 42 // Compiler knows that lambda passed to 'synchronize' is called
// exactly once, so no reassignment is reported
}
println(x) // Compiler knows that lambda will be definitely called, performing
// initialization, so 'x' is considered to be initialized here
}
'트러블슈팅' 카테고리의 다른 글
[Aws] s3 메타데이터 설정하기 (0) | 2020.11.13 |
---|---|
[JPA] OneToMany 에서 child 를 지웠는데 update 쿼리가 날아간다고? (0) | 2020.11.05 |
[Gradle] 라이브러리 버전 충돌(버전이 여러개인 경우) (0) | 2020.07.14 |
[Aws] s3 cors 에러 (0) | 2020.07.03 |
[Python] pandas.read_csv 에서 ssl 오류 (0) | 2020.04.04 |