is
와 !is
연산자
is
는 자바의 instanctof
이고 !is
는 instanceof
하고 negation 한 것과 같다.분기문에 적용하면 Smart casts 가 적용되어 대상 타입으로 캐스팅된다.
Smart casts
- 코틀린에서는 대부분의 경우 명시적인 casting 연산을 해줘야 하는 경우가 없습니다.
- 기본
fun demo(x: Any) { if (x is String) { print(x.length) // x is automatically cast to String } }
- negation 후 return 한 경우
if (x !is String) return print(x.length) // x is automatically cast to String
- && 혹은 || 의 오른쪽에서
// x is automatically cast to String on the right-hand side of `||` if (x !is String || x.length == 0) return // x is automatically cast to String on the right-hand side of `&&` if (x is String && x.length > 0) { print(x.length) // x is automatically cast to String }
when
절,while
절 에서도!
when (x) { is Int -> print(x + 1) is String -> print(x.length + 1) is IntArray -> print(x.sum()) }
- 짱짱 컴파일러가 캐스팅 하려는 순간마다 알아서 해줄 것입니다.
구체적으로는
val/val
, 지역변수/property
에 따라 다른 전략을 사용합니다. 이는 나중에 공부합시다!
“Unsafe” cast operation
보통, 캐스팅은 캐스팅이 불가능 할 때 예외를 터트립니다. 그래서 그냥 “Unsafe”라고 부르기로 했습니다.
unsafe casting 은 중위 연산자
as
로 합니다.val x: String = y as String
val x: String? = y as String?
“Safe” (nullable) cast operator
예외를 막을려면 safe 한 캐스팅 연산자
as?
를 활용하면 됩니다. as?
는 캐스팅을 못 할때 null
을 반환합니다.val x: String? = y as? String
타입 이레이저와 제네릭 타입 체크
코틀린은 제네릭의 타입 정보를 컴파일 타임에 지워버린다 (type erasure)
그래서 런타임에 제네릭 타입의 instance 는 실제 type argument 에 대한 정보를 전혀 들고 있지 않다.
예를 들어
List<Foo>
는 타입 이레이저를 통해 그냥 List<*>
이다.일반적으로 런타임에 이를 확인할 방법은 없다 (아마 super type token 쓰면 될듯?)
때문에 컴파일러는 is 를 제네릭에 사용하는 방식을 제한한다.
e.g. )
ints is List<Int>
or list is T
(type parameter)하지만 star-projected type 을 사용할 수 있다!
if (something is List<*>) { something.forEach { println(it) } // The items are typed as `Any?` }
inline functions with reified type parameters
inline fun <reified A, reified B> Pair<*, *>.asPairOf(): Pair<A, B>? { if (first !is A || second !is B) return null return first as A to second as B } val somePair: Pair<Any?, Any?> = "items" to listOf(1, 2, 3) val stringToSomething = somePair.asPairOf<String, Any>() val stringToInt = somePair.asPairOf<String, Int>() val stringToList = somePair.asPairOf<String, List<*>>() val stringToStringList = somePair.asPairOf<String, List<String>>() // Compiles but breaks type safety! // Expand the sample for more details fun main() { println("stringToSomething = " + stringToSomething) println("stringToInt = " + stringToInt) println("stringToList = " + stringToList) println("stringToStringList = " + stringToStringList) //println(stringToStringList?.second?.forEach() {it.length}) // This will throw ClassCastException as list items are not String }
나중에 공부하자
Unchecked casts
나중에 공부하자