Kotlin学习笔记之基础总结

前面讲解了

嗯,好像还漏了一些基础。 如:

  • 基本类型的定义与转换
  • 数据的返回和跳转
  • 包名冲突的解决方案

在这里将剩下的基础都简要归纳下,参考于https://www.kotlincn.net/docs


基本类型

数字

  • Kotlin 提供了如下的内置类型来表示数字
Type Bit width
Double 64
Float 32
Long 64
Int 32
Short 16
Byte 8
  • 数值常量字面值有以下几种:

    • 十进制: 123 (Long 类型用大写 L 标记: 123L)
    • 十六进制: 0x0F
    • 二进制: 0b00001011
    • 不支持八进制
    • Kotlin 同样支持浮点数的常规表示方法:
      • 默认 double:123.5、123.5e10
      • Float 用 f 或者 F 标记: 123.5f
  • 注:自 1.1 起,你可以使用下划线使数字常量更易读:

    1
    2
    3
    4
    5
    val oneMillion = 1_000_000
    val creditCardNumber = 1234_5678_9012_3456L
    val socialSecurityNumber = 999_99_9999L
    val hexBytes = 0xFF_EC_DE_5E
    val bytes = 0b11010010_01101001_10010100_10010010
  • 表示方式
    在 Java 平台数字是物理存储为 JVM 的原生类型,除非我们需要一个可空的引用(如 Int?)或泛型。 后者情况下会把数字装箱。
    注意数字装箱不必保留同一性:

    1
    2
    3
    4
    5
    val a: Int = 10000
    print(a === a) // 输出“true”
    val boxedA: Int? = a
    val anotherBoxedA: Int? = a
    print(boxedA === anotherBoxedA) // !!!输出“false”!!!

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

    1
    2
    3
    4
    5
    val a: Int = 10000
    print(a == a) // 输出“true”
    val boxedA: Int? = a
    val anotherBoxedA: Int? = a
    print(boxedA == anotherBoxedA) // 输出“true”
  • 显示转换提供了以下方法

    • toByte(): Byte
    • toShort(): Short
    • toInt(): Int
    • toLong(): Long
    • toFloat(): Float
    • toDouble(): Double
    • toChar(): Char
      //例如:
      1
      2
      val b: Byte = 1
      val i: Int = b.toInt()
  • 用于 Int 和 Long的完整的位运算列表

    • shl(bits) – 有符号左移 (Java 的 <<)
    • shr(bits) – 有符号右移 (Java 的 >>)
    • ushr(bits) – 无符号右移 (Java 的 >>>)
    • and(bits) – 位与
    • or(bits) – 位或
    • xor(bits) – 位异或
    • inv() – 位非

字符Char

  • 字符字面值用单引号括起来: ‘1’ (和java类似)
  • 特殊字符可以用反斜杠转义。 支持这几个转义序列:\t、 \b、\n、\r、'、"、\ 和 $。 编码其他字符要用 Unicode 转义序列语法:’\uFF00’。
  • 可以用以下方式将Char 转换为 Int
    1
    2
    3
    4
    5
    fun decimalDigitValue(c: Char): Int {
    if (c !in '0'..'9')
    throw IllegalArgumentException("Out of range")
    return c.toInt() - '0'.toInt() // 显式转换为数字
    }

布尔Boolean

和java类似,内置:

  • || 逻辑或
  • && 逻辑与
  • ! 逻辑非

数组

  • 数组在 Kotlin 中使用 Array 类来表示,它定义了 get 和 set 函数(按照运算符重载约定这会转变为 [])和 size 属性,以及一些其他有用的成员函数:

    1
    2
    3
    4
    5
    6
    7
    8
    class Array<T> private constructor() {
    val size: Int
    operator fun get(index: Int): T
    operator fun set(index: Int, value: T): Unit

    operator fun iterator(): Iterator<T>
    // ……
    }
  • 创建数组的方法

    • 使用arrayOf(1, 2, 3) 创建了 array [1, 2, 3]
      1
      var arr = arrayOf(1, 2, 3)
    • 使用arrayOfNulls创建长度为3元素为null的Int集合
      1
      var arr : Array<Int?> = arrayOfNulls(3)
    • 利用接受数组大小和一个函数参数的工厂函数
      1
      2
      // 创建一个 Array<String> 初始化为 ["0", "1", "4", "9", "16"]
      val asc = Array(5, { i -> (i * i).toString() })
  • Kotlin 也有无装箱开销的专门的类来表示原生类型数组: ByteArray、 ShortArray、IntArray 等等
    这些类和 Array 并没有继承关系,但是它们有同样的方法属性集。

字符串

  • 字符串用 String 类型表示。字符串是不可变的。

    • 元素可以使用str[i]访问
    • 元素也可以使用for遍历
      1
      2
      3
      for (c in str) {
      println(c)
      }
  • 支持java中的转义字符

  • 原生字符串 使用三个引号(”””)分界符括起来,内部没有转义并且可以包含换行和任何其他字符:

    1
    2
    3
    4
    val text = """
    for (c in "foo")
    print(c)
    """
    • 你可以使用 trimMargin() 函数去除前导空格(默认 | 用作边界前缀,但你可以选择其他字符并作为参数传入,比如 trimMargin(“>”)。)
      1
      2
      3
      4
      5
      6
      val text = """
      |Tell me and I forget.
      |Teach me and I remember.
      |Involve me and I learn.
      |(Benjamin Franklin)
      """.trimMargin()
  • 字符串模板

    • $ (属性 或 (表达式))读取属性值或者表达式返回值

      1
      2
      3
      4
      5
      val i = 10
      val s = "i = $i" // 求值结果为 "i = 10"

      val s = "abc"
      val str = "$s.length is ${s.length}" // 求值结果为 "abc.length is 3"
    • 你需要在原生字符串中表示字面值 $ 字符(它不支持反斜杠转义),你可以用下列语法:

      1
      2
      3
      val price = """
      ${'$'}9.99
      """

包相关操作

  • 源文件通常以包声明开头:
    1
    2
    3
    4
    5
    6
    7
    package foo.bar

    fun baz() {}

    class Goo {}

    // ……
    源文件所有内容(无论是类还是函数)都包含在声明的包内。 所以上例中 baz() 的全名是 foo.bar.baz、Goo 的全名是 foo.bar.Goo。

如果没有指明包,该文件的内容属于无名字的默认包。

  • 默认导入
    有多个包会默认导入到每个 Kotlin 文件中:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    kotlin.*
    kotlin.annotation.*
    kotlin.collections.*
    kotlin.comparisons.* (自 1.1 起)
    kotlin.io.*
    kotlin.ranges.*
    kotlin.sequences.*
    kotlin.text.*
    ~

    根据目标平台还会导入额外的包:
    JVM:

    1
    2
    java.lang.*
    kotlin.jvm.*

    JS:

    1
    kotlin.js.*
  • 导入

    • 导入一个单独的名字:
      1
      mport foo.Bar // 现在 Bar 可以不用限定符访问
    • 导入一个作用域下的所有内容(包、类、对象等):
      1
      import foo.* // “foo”中的一切都可访问
    • 如果出现名字冲突,可以使用 as 关键字在本地重命名冲突项来消歧义:
      1
      2
      import foo.Bar // Bar 可访问
      import bar.Bar as bBar // bBar 代表“bar.Bar”

返回和跳转

  • Kotlin 有三种结构化跳转表达式:

    • return。默认从最直接包围它的函数或者匿名函数返回。
    • break。终止最直接包围它的循环。
    • continue。继续下一次最直接包围它的循环。
  • 所有这些表达式都可以用作更大表达式的一部分:

    1
    val s = person.name ?: return
  • label@ 标签结合使用

    • Break 与 Continue 标签
      在 Kotlin 中任何表达式都可以用标签(label)来标记。 标签的格式为标识符后跟 @ 符号,例如:abc@、fooBar@都是有效的标签
      1
      2
      3
      4
      5
      loop@ for (i in 1..100) {
      for (j in 1..100) {
      if (……) break@loop //该break执行将会除非第一个for停止
      }
      }
    • 标签处返回 语法:return@label value
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      //让return不直接返回到最外层的foo方法的做法
      fun foo() {
      ints.forEach lit@ {
      if (it == 0) return@lit (或@forEach)
      print(it)
      }
      }
      //添加匿名方法 返回给匿名方法
      fun foo() {
      ints.forEach(fun(value: Int) {
      if (value == 0) return // local return to the caller of the anonymous fun, i.e. the forEach loop
      print(value)
      })
      }