二元操作符
表达式
转换
a + b
a.plus(b)
a - b
a.minus(b)
a * b
a.times(b)
a / b
a.div(b)
a % b
a.mod(b)
a..b
a.rangeTo(b)
编译器只是解决了该表中翻译为列的表达式
表达式
转换
a in b
b.contains(a)
a !in b
!b.contains(a)
in
和
!in
的产生步骤是一样的,但参数顺序是相反的。
运算符重载
148
标志
转换
a[i]
a.get(i)
a[i, j]
a.get(i, j)
a[i_1, ..., i_n]
a.get(i_1, ... , i_n)
a[i] = b
a.set(i, b)
a[i,j] =b
a.set(i, j, b)
a[i_1, ... , i_n] = b
a.set(i_1,... ,o_n,b)
方括号被转换为
get set
函数
标志
转换
a(i)
a.invoke(i)
a(i, j)
a.invoke(i, j)
a(i_1, ... , i_n)
a.invoke(i_1, ..., i_n)
括号被转换为带有正确参数的
invoke
参数
表达式
转换
a += b
a.plusAssign(b)
a -= b
a.minusAssign(b)
a *= b
a.timesAssign(b)
a /= b
a.divAssign(b)
a %= b
a.modAssign(b)
在分配
a+= b
时编译器是下面这样实现的:
右边列的函数是否可用 对应的二元函数
(
比如
plus() )
是否也可用
,
不可用在报告
错误 确定它的返回值是
Unit
否则报告错误 生成
a.plusAssign(b)
否则
试着生成
a=a+b
代码
Note: assignments are NOT expressions in Kotlin.
表达式
转换
a == b
a?.equals(b) ?: b.identityEquals(null)
a != b
!(a?.equals(b) ?: b.identityEquals(null))
运算符重载
149
注意
=== !==
是不允许重载的
==
操作符有俩点特别:
它被翻译成一个复杂的表达式,用于筛选空值,而且
null == null
是真
它需要带有特定签名的函数,而不仅仅是特定名称的函数,下面这样:
fun
equals
(other: Any?)
:
Boolean
或者用相同的参数列表和返回类型的扩展功能
标志
转换
a > b
|
a.compareTo(b) > 0 a < b
|
a.compareTo(b) < 0 a >= b
|
a.compareTo(b)
>= 0 a <= b
|
a.compareTo(b) <= 0
所有的比较都转换为
compareTo
的调用,这个函数需要返回
Int
值
命名函数的中缀调用
我们可以通过
中缀函数的调用
来模拟自定义中缀操作符
运算符重载
150
空安全
空安全
可空类型和非空类型
Kotlin
类型系统致力于消灭空引用。
在许多语言中都存在的一个大陷阱包括
java
,就是访问一个空引用的成员,结果会
有空引用异常。在
java
中这就是
NullPointerException
或者叫
NPE
Kotlin
类型系统致力与消灭
NullPointerException
异常。唯一可能引起
NPE
异常的可能是:
明确调用
throw NullPointerException()
外部
java
代码引起 一些前后矛
盾的初始化
(
在构造函数中没初始化的成员在其它地方使用
)
在
Kotlin
类型系统中可以为空和不可为空的引用是不同的。比如,普通的
String
类型的变量不能为空:
var
a
: String =
"abc"
a =
null
//
编译错误
允许为空,我们必须把它声明为可空的变量:
var
b
: String? =
"abc"
b =
null
现在你可以调用
a
的方法,而不用担心
NPE
异常了:
val
l
= a.length()
但如果你想使用
b
调用同样的方法就有可能报错了:
val
l
= b.length()
//
错误:
b
不可为空
但我们任然想要调用方法,有些办法可以解决。
151
空安全
在条件中检查
null
首先,你可以检查
b
是否为空,并且分开处理下面选项:
val
l
=
if
(b !=
null
) b.length()
else
-1
编译器会跟踪你检查的信息并允许在
if
中调用
length()
。更复杂的条件也是可以
的:
if
(b !=
null
&& b.length() >
0
)
print(
"Stirng of length ${b.length}"
)
else
print(
"Empty string"
)
注意只有在
b
是不可变时才可以
安全调用
第二个选择就是使用安全操作符,
?.
:
b?.length()
如果
b
不为空则返回长度,否则返回空。这个表达式的的类型是
Int?
安全调用在链式调用是是很有用的。比如,如果
Bob
是一个雇员可能分配部门
(
也
可能不分配
)
,如果我们想获取
Bob
的部门名作为名字的前缀,就可以这样做:
bob?.department?.head?.name
这样的调用链在任何一个属性为空都会返回空。