[원본] https://kotlinlang.org/docs/typecasts.html
is, !is
변수 is 타입 : 리턴 = true/false
fun main() {
var obj = "가나다라마"
if (obj is String) {
println(obj.length)
}
if (obj !is String) { // 다음과 같습니다 : !(obj is String)
println("Not a String")
} else {
println(obj.length)
}
}
5
5
스마트케스트
아래 경우에는 정해지지 않은 타입이라도 유추할 수 있습니다.
Any : 정해지지 않은 타입
is연산자를 통해서 타입을 보장할 수 있는 경우, 해당 타입으로 케스트(사용)할 수 있습니다.
경우1 : if 이하에서..
fun main(){
type("문자열")
type(1)
}
fun type(x : Any) {
if (x is String) { // is String을 통과했으므로
println(x.length) // x가 문자열이라고 단정할 수 있습니다.
} else {
print("문자열이 아님")
}
}
3
문자열이 아님
경우2 : return이하에서.. (결과는 1과 동일)
fun main(){
type("문자열")
type(1)
}
fun type(x : Any) {
if (x !is String) {
println("문자열이 아님")
return
} // !is String를 통과하지 못한다면,
println(x.length) // x가 문자열이라고 단정할 수 있습니다.
}
경우3 : if문이 And, Or로 연결되었다면..
fun main(){
type("문자열")
type(1)
type("")
}
fun type(x : Any) {
// if의 조건에서, `||`보다 왼편에 있는 조건을 만족해야, 오른쪽 조건을 살펴본다.
// 따라서 x.length는 에러가 나지 않는다.
if (x !is String || x.length == 0){
println("길이가 없습니다.")
return
}
// if의 조건에서, '&&'를 만족했다면 x.lenght > 0에서 x를 String으로 유추 할 수 있다.
if (x is String && x.length > 0) {
println(x.length) // x를 String으로 인식한다.
}
}
3
길이가 없습니다.
길이가 없습니다.
안전하지 않은 캐스팅 as!
excpetion(예외, 오류)이 발생할 수 있는 캐스팅을 '안전하지 않은 캐스팅'이라고 합니다. as를 사용합니다.
fun main(){
val y: String? = null
// 예외처리가 발생합니다.
//val x: String = y as String
// 해결1 : 입/출력 모두 nullalbe로 만듭니다.
val x: String? = y as String?
// 해결2 : 변경과정에서 예외처리가 발생하는 것을 막으려면 as?를 이용해서 보호합니다.
val z: String? = y as? String
println(x)
}
null
유형 삭제 및 일반 유형 검사
컴파일하는 동안 제네릭정보가 삭제됩니다. 예를들어 List<Foo> 는 List<*>가 됩니다. 런타임에 제네릭이 특정형식을 가지고 있는지 알 수 없습니다. 따라서 해당형식이 List인지 확인하려면 List<*>를 사용합니다.
※ List역시 Class로 관리된다는 점을 고려한다면, is연산자로 자동캐스팅된다는 점은 놀라운 점이 아닙니다.
컴파일시에 제네릭(<>)은 삭제된다.
이 사실만 명심하면 될 것 같습니다.
fun main(){
var something = listOf(1, 2, 3, 4, 5)
if (something is List<*>) {
something.forEach { println(it) } // `Any?`로 유추됩니다.
}
}
1
2
3
4
5
is 연산자를 통해서 type을 캐스팅 할 수도 있습니다. (위 예제어서 <*>만 생략됨)
fun main(){
var something = arrayListOf("하나", "둘", "셋")
var anything = listOf("넷", "다섯", "여섯")
handleStrings(something)
handleStrings(anything)
}
fun handleStrings(list: List<String>) {
if (list is ArrayList) {
// `list`가 `ArrayList<String>`로 자동캐스팅 됩니다.
list.forEach { print("$it ") }
println()
}else{
print("ArrayList가 아님니다.")
}
}
하나 둘 셋
ArrayList가 아님니다.
※ 아래 예제는 원문에서 발췌한 코드입니다.
예문의 내용은 제네릭이 런타임에서 삭제되어있다는 내용이며, 함수파트를 학습한 뒤에 이해할 수 있습니다.
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
}
확인되지 않는 캐스트
본문의 예문은 "readDictionary함수가 반환하는 타입"과 "마지막 줄에서 반환받는 타입"이 다른 것을 알 수 있습니다. 이 경우 일단 컴파일이 되기는 하지만, 컴파일러에서 경고를 낼 수 있습니다. 경고를 없애기 위해서 다음을 사용합니다.
@Suppress("UNCHECKED_CAST")
fun readDictionary(file: File): Map<String, *> = file.inputStream().use {
TODO("Read a mapping of strings to arbitrary elements.")
}
// We saved a map with `Int`s into this file
val intsFile = File("ints.dictionary")
// Warning: Unchecked cast: `Map<String, *>` to `Map<String, Int>`
val intsDictionary: Map<String, Int> = readDictionary(intsFile) as Map<String, Int>
'코틀린' 카테고리의 다른 글
[kotlinlang.org] 한글화. 1 기본 유형 (0) | 2022.05.06 |
---|---|
[kotlinlang.org] 한글화. 0 기본 구문 (0) | 2022.05.05 |
[Youtube DiMo] 31강. 동기처리(마지막) (0) | 2022.05.03 |
[Youtube DiMo] 30강. 비트연산 (0) | 2022.05.03 |
[Youtube DiMo] 29강. 변수 (0) | 2022.05.03 |
댓글