Kotlin进阶之类型检查、This表达式

Posted by AlexWan on 2017-07-17

类型检查与转型

is和!is操作符

使用is!is在运行时检查对象是否满足给定类型。

if (obj is String) {
print(obj.length)
}
if (obj !is String) { // same as !(obj is String)
print("Not a String")
}
else {
print(obj.length)
}

智能转换

在很多情况中,Kotlin无须使用显式转换操作,因为编译器跟踪不变值的is检查,自动插入(安全地)转换。

fun demo(x: Any){
if(x is String){
print(x.length) // x 自动会转为String
}
}

如果是取反操作导致return,编译器也能进行职能转换

if (x !is String) return
print(x.length) // x 自动转为String

或者在||&&右侧

// 在`||` x自动转为String
if (x !is String || x.length == 0) return
// 在`&&` x自动转为String
if (x is String && x.length > 0) {
print(x.length) // x 自动转为String
}

智能转换同样适应于when表达式while循环

when(x){
is Int -> print(x + 1)
is String -> print(x.length + 1)
is IntArray -> print(x.sum())
}

当编译器不能保证变量在检查和使用期间不能变化,则智能转换无效。

更加特殊的,智能转换适应下面规则:

  • val 局部变量 - always
  • val 属性 - 如果属性为私有、内部、在与声明的相同module检查。智能转换不适应于open属性,自定义getter的属性。
  • var 局部变量 - 在检查与使用之间没有被修改,并且修改后没有被Lambda中捕获。
  • var 属性 - never

“非安全”转换操作

通常,如果不能转换,转换操作符会抛出异常。因此称之为非安全。Kotlin使用as操作符完成非安全转换(查看操作符优先级

val x: String = y as String

null无法转为String,因为类型是非空类型。比如,如果y为null,上面的代码则会抛出异常。为了满足Java转换语义,Kotlin需要在转换右侧添加可为空类型

val x: String? = y as String?

“安全”(可为空)转换操作

避免抛出异常,可以使用as?安全转换操作,失败返回null

val x: String? = y as? String

尽管事实上as?右侧为非空类型String,转换结果可为空。

This表达式

Kotlin使用this表达式表示当前接收者,

如果this没有限定符,指向最内闭合作用域。在其他作用域使用this,则需要使用label限定符

this限定符

使用this@label访问作用域(如class扩展函数接收者表示的函数字面量)外部的this,@label表示this来源作用域的label

class A { // 隐性 label @A
inner class B { // 隐性 label @B
fun Int.foo() { // 隐性 label @foo
val a = this@A // A's this
val b = this@B // B's this
val c = this // foo()的接收者, Int
val c1 = this@foo // foo()的接收者, Int
val funLit = lambda@ fun String.() {
val d = this // funLit的接收者
}
val funLit2 = { s: String ->
// foo()的接收者, 因为闭合Lambda表达式没有任何接收者
val d1 = this
}
}
}
}