오늘은 함수들을 열어보다 처음 보는 예약어를 발견했습니다.
contract {
returns() implies value
}
그렇기에 오늘은 이 예약어들을 알아볼까 합니다.
Contract의 기능
fun String?.isNotNull(): Boolean = this != null
fun foo(s: String?) {
if (s != null) s.length
if (s.isNotNull()) s?.length // No smartcast :(
}
공식문서에서는 contact가 기존의 스마트케스팅을 할 때 해당 스코프를 나가게 될 경우 스마트 캐스팅이 되지 않았던 점이 있었습니다. 그래서 코틀린은 1.3 버전부터 해당기능을 지원하는 contract 함수를 이용할 수 있게 되었습니다.
이 함수의 장점은 한번 contact가 포함된 함수를 호출한 로직부터는 contract에 정의한 조건을 계속 명시하지 않아도 된다는 점입니다.
Contract의 사용방법
@ExperimentalContracts
function {
contract {
Effect
}
}
위와 같은 양식으로 작성합니다. Effect 같은 경우 사전 조건과 사후 조건을 정의하는 데 사용되는 키워드입니다. 사전 조건은 함수가 실행되기 전에 만족해야 하는 조건이며, 사후 조건은 함수가 실행된 후에 만족해야 하는 조건입니다. 또한 어노테이션 같은 경우 어노테이션으로 실행되는 모든 곳에 어노테이션을 작성해줘야 합니다.
Effect 같은 경우 여러 방법으로 표현할 수 있습니다.
returns
returns(true) implies (boolean)
조건식을 만족하는지 확인 맞다면 해다 조건의 함수 밖에서도 스마트캐스팅용으로 이용가능합니다. 참고로 inplies는 Boolean값을 받지만 유효한 값은 null 검사( == null ,! = null), 인스턴스 검사( is ,! is ), 논리 연산자( && , | | , ! )등 Kotlin 표현식의 하위 집합만 허용됩니다.
예제
@ExperimentalContracts
fun isNotNull(value: Any?): Boolean {
contract {
returns(true) implies (value != null)
}
return value != null
}
@ExperimentalContracts
fun main(args: Array<String>) {
val nullableInt: Int? = 5
//type 안맞음
//val intNum : Int = nullableInt
if (isNotNull(nullableInt)) {
val nonNullInt: Int = nullableInt
}
}
위 코드처럼 nullableInt가 null이 아닌 것이 확인되었으니 자료형이 Int인 nonNullInt에 집어넣을 수 있습니다. 이렇게 될 수 있는 것은 contract로 이미 null이 아닌 것을 확인했기 때문입니다.
callsInPlace
callsInPlace(lambdaFunc, kotlin.contracts.InvocationKind.EXACTLY_ONCE)
callsInPlace는 람다 함수를 사용할 때, 그 함수의 호출 횟수를 명시적으로 컴파일러에게 이해시켜 주기 위해 사용합니다.
예제
@ExperimentalContracts
fun invokeLambda(lambdaFunc: () -> Unit) {
contract{
callsInPlace(lambdaFunc, kotlin.contracts.InvocationKind.EXACTLY_ONCE)
}
lambdaFunc()
}
@ExperimentalContracts
fun main(){
val stringConstant: String
invokeLambda {
//에러발생 X
stringConstant = "hello world"
}
println(stringConstant)
}
위 코드는 callsInPlace가 있는 덕분에 stringConstant의 값을 지정할 수 있습니다. 기존에는 해당변수가 val이기에 몇 번이나 호출할지 모른다는 것 때문에 에러가 생겼습니다. 그렇지만 이번에는 정확히 한번 호출한다는 InvocationKind.EXACTLY_ONCE덕분에 에러가 생기지 않고 print문으로 해당값을 출력할 수 있는 것입니다.
오늘은 이렇게 contract에 대해서 알아보았습니다. 분명 매번 널 체크를 안 해줘도 된다는 것은 좋지만 매번 어노테이션을 써줘야 되고 또한 어노테이션이름이 실험적 contract이기 때문에 사용하기에 무리가 있어 보입니다. 추후 어노테이션이 없어진다면 유용하게 쓸 수 있을 것 같습니다.
참고
https://kotlinlang.org/docs/whatsnew13.html#contracts
https://www.baeldung.com/kotlin/contracts
https://maivve.tistory.com/359
'코틀린 > 문법및 라이브러리' 카테고리의 다른 글
[Kotlin] 여러 종류의 반복문 (0) | 2023.08.04 |
---|---|
[Kotlin] 교집합(intersect), 합집합(union), 차집합(subtract) (0) | 2023.07.31 |
[Kotlin] Result class 가 뭐지? (0) | 2023.07.26 |
[Kotlin] 시퀀스(Sequence) 파보기 (0) | 2023.07.13 |
[Kotlin] 콜렉션(Collection) 파보기 (0) | 2023.07.12 |