Kotlin 小记-2-基本类型与跳转

225 阅读3分钟

在 Java 平台数字是物理存储为 JVM 的原生类型,除非我们需要一个可空的引用(如 Int?)或泛型。 后者情况下会把数字装箱。 注意数字装箱不一定保留同一性:

val a: Int = 10000
println(a === a) // 输出“true”
val boxedA: Int? = a
val anotherBoxedA: Int? = a
println(boxedA === anotherBoxedA) // !!!输出“false”!!!

另一方面,它保留了相等性:

val a: Int = 10000
println(a == a) // 输出“true”
val boxedA: Int? = a
val anotherBoxedA: Int? = a
println(boxedA == anotherBoxedA) // 输出“true”

显式转换

较小的类型不能隐式转换为较大的类型。 这意味着在不进行显式转换的情况下我们不能把 Byte 型值赋给一个 Int 变量。

val b: Byte = 1 // OK, 字面值是静态检测的
val i: Int = b // 错误

我们可以显式转换来拓宽数字

val i: Int = b.toInt() // OK:显式拓宽
print(i)

每个数字类型支持如下的转换:

toByte(): Byte
toShort(): Short
toInt(): Int
toLong(): Long
toFloat(): Float
toDouble(): Double
toChar(): Char

缺乏隐式类型转换很少会引起注意,因为类型会从上下文推断出来,而算术运算会有重载做适当转换,例如:

val l = 1L + 3 // Long + Int => Long

字符用 Char 类型表示。它们不能直接当作数字

Kotlin 也有无装箱开销的专门的类来表示原生类型数组: ByteArray、 ShortArray、IntArray 等等。这些类与 Array 并没有继承关系,但是它们有同样的方法属性集。它们也都有相应的工厂方法:

val x: IntArray = intArrayOf(1, 2, 3)
x[0] = x[1] + x[2]
// 大小为 5、值为 [0, 0, 0, 0, 0] 的整型数组
val arr = IntArray(5)

// 例如:用常量初始化数组中的值
// 大小为 5、值为 [42, 42, 42, 42, 42] 的整型数组
val arr = IntArray(5) { 42 }

// 例如:使用 lambda 表达式初始化数组中的值
// 大小为 5、值为 [0, 1, 2, 3, 4] 的整型数组(值初始化为其索引值)
var arr = IntArray(5) { it * 1 }

导入: 如果导入的如果出现名字冲突,可以使用 as 关键字在本地重命名冲突项来消歧义:

import org.example.Message // Message 可访问
import org.test.Message as testMessage // testMessage 代表“org.test.Message”

在 Kotlin 中任何表达式都可以用标签(label)来标记。 标签的格式为标识符后跟 @ 符号,例如:abc@、fooBar@都是有效的标签(参见语法)。 要为一个表达式加标签,我们只要在其前加标签即可。

loop@for (i in 1..10) {
     for (j in 1..10) {
        if(j == 5) break@loop
        print(j)
    }
}

// 只会打印出1234
listOf(1, 2, 3, 4, 5).forEach hehe@{
        if (it == 3) return@hehe 
        // 局部返回到该 lambda 表达式的调用者,即 forEach 循环
        // 这里面是不能使用break 或者 continue 的
        print(it)
    }

如果想实现在循环中break的功能可以通过增加另一层嵌套 lambda 表达式并从其中非局部返回来模拟:

fun foo() {
    run loop@{
        listOf(1, 2, 3, 4, 5).forEach {
            if (it == 3) return@loop // 从传入 run 的 lambda 表达式非局部返回
            print(it)
        }
    }
    print(" done with nested loop")
}

当要返一个回值的时候,解析器优先选用标签限制的 return,即

return@a 1

意为“返回 1 到 @a”,而不是“返回一个标签标注的表达式 (@a 1)”。(暂时不知道有啥用处)