Kotlin
Type Checks and Casts: 'is' and 'as'
Swift
|
is and !is Operators
|
if (obj is String) {
print(obj.length)
}
if (obj !is String) { // same as !(obj is String)
print("Not a String")
}
else {
print(obj.length)
}
|
if (obj is String) {
print(obj.length)
}
if (obj !is String) { // same as !(obj is String)
print("Not a String")
}
else {
print(obj.length)
}
|
Smart Casts
|
fun demo(x: Any) {
if (x is String) {
print(x.length) // x is automatically cast to String
}
}
|
func demo(x: Any) {
if (x is String) {
print(x.length) // x is automatically cast to String
}
}
|
if (x !is String) return
print(x.length) // x is automatically cast to String
|
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
}
|
// 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 (x) {
is Int -> print(x + 1)
is String -> print(x.length + 1)
is IntArray -> print(x.sum())
}
|
when (x) {
is Int -> print(x + 1)
is String -> print(x.length + 1)
is IntArray -> print(x.sum())
}
|
"Unsafe" cast operator
|
val x: String = y as String
|
let x: String = y as String
|
val x: String? = y as String?
|
let x: String? = y as String?
|
"Safe" (nullable) cast operator
|
val x: String? = y as? String
|
let x: String? = y as? String
|
Type erasure and generic type checks
|
if (something is List<*>) {
something.forEach { println(it) } // The items are typed as `Any?`
}
|
if (something is List<*>) {
something.forEach { print(it) } // The items are typed as `Any?`
}
|
fun handleStrings(list: List<String>) {
if (list is ArrayList) {
// `list` is smart-cast to `ArrayList<String>`
}
}
|
func handleStrings(list: List<String>) {
if (list is ArrayList) {
// `list` is smart-cast to `ArrayList<String>`
}
}
|
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>>() // Breaks type safety!
|
inline func <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
}
let somePair: Pair<Any?, Any?> = "items" to [1, 2, 3]
let stringToSomething = somePair.asPairOf<String, Any>()
let stringToInt = somePair.asPairOf<String, Int>()
let stringToList = somePair.asPairOf<String, List<*>>()
let stringToStringList = somePair.asPairOf<String, List<String>>() // Breaks type safety!
|
Unchecked casts
|
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 that 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>
|
func 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 that file
let intsFile = File("ints.dictionary")
// Warning: Unchecked cast: `Map<String, *>` to `Map<String, Int>`
let intsDictionary: Map<String, Int> = readDictionary(intsFile) as Map<String, Int>
|
inline fun <reified T> List<*>.asListOfType(): List<T>? =
if (all { it is T })
@Suppress("UNCHECKED_CAST")
this as List<T> else
null
|
inline func <reified T> List<*>.asListOfType(): List<T>? =
if (all { $0 is T })
@Suppress("UNCHECKED_CAST")
this as List<T> else
null
|