Kotlin數據類型

在Kotlin中,一切都是一個對象,可以在任何變量上調用成員函數和屬性。 一些類型是內置的,因爲它們的實現被優化,但是它們看起來像普通類。 在本節中,我們將介紹描述Kotlin中的大多數類型:數字,字符,布爾和數組等等。

數字類型

Kotlin以接近Java的方式來處理數字,但不完全相同。 例如,數字沒有隱含的擴展轉換,在某些情況下,字面量略有不同。

Kotlin提供以下代表數字的內置類型(這接近Java):

類型

位寬度

Double

64

Float

32

Long

64

Int

32

Short

16

Byte

8

注意,字符不是Kotlin中的數字。

字面常量/文字常量

對於整數值,有以下幾種字面常量:

  • 整數:123
  • 長整數由大寫L標記:123L
  • 十六進制:0x0F
  • 二進制:0b00001011

注意:不支持八進制字面常量。

Kotlin還支持一個常規的浮點數符號:

  • 默認爲Double123.5, 123.5e10
  • 浮點數標記爲fF123.5f

數字字面常量的下劃線

可以使用下劃線使數字常量更易讀:

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?)或涉及泛型。 在後一種情況下,數字是裝箱的。

請注意,裝箱數字不一定保持身份:

val a: Int = 10000
print(a === a) // Prints 'true'
val boxedA: Int? = a
val anotherBoxedA: Int? = a
print(boxedA === anotherBoxedA) // !!!Prints 'false'!!!

另一方面,它保持相等:

val a: Int = 10000
print(a == a) // Prints 'true'
val boxedA: Int? = a
val anotherBoxedA: Int? = a
print(boxedA == anotherBoxedA) // Prints 'true'

顯式轉換

由於不同的表示,較小的類型不是較大的類型的子類型,就會有以下類型的麻煩:

// Hypothetical code, does not actually compile:
val a: Int? = 1 // A boxed Int (java.lang.Integer)
val b: Long? = a // implicit conversion yields a boxed Long (java.lang.Long)
print(a == b) // Surprise! This prints "false" as Long's equals() check for other part to be Long as well

因此,較小的類型不會被隱式轉換爲更大的類型。 這意味着不能在沒有顯式轉換的情況下將Byte類型的值賦給Int類型的變量。

val b: Byte = 1 // OK, literals are checked statically
val i: Int = b // ERROR

可以使用顯式轉換來擴寬數字 -

val i: Int = b.toInt() // OK: explicitly widened

每個數字類型都支持以下轉換:

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

缺少隱式轉換是很少引人注意的,因爲類型是從上下文推斷出來的,而算術運算則被重載爲適當的轉換,例如 -

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

操作

Kotlin支持對數字進行的算術運算的標準集合,它們被聲明爲適當類的成員(但編譯器將調用優化爲相應的指令)。請參閱操作符重載。

對於按位操作,它們沒有特殊的字符,但是隻能命名爲可以以中綴形式調用的函數,例如:

val x = (1 shl 2) and 0x000FF000

以下是按位操作的完整列表(僅適用於IntLong):

  • shl(bits) – 有符號向左移 (Java的<<)
  • shr(bits) – 有符號向右移 (Java’s >>)
  • ushr(bits) – 無符號向右移 (Java’s >>>)
  • and(bits) – 位運算符and
  • or(bits) – 位運算符or
  • xor(bits) – 位運算符xor
  • inv() – 位運算符」取反」

字符

字符由Char類型表示,它們不能直接被視爲數字

fun check(c: Char) {
    if (c == 1) { // ERROR: incompatible types
        // ...
    }
}

字符文字用單引號表示:'1'。 可以使用反斜槓轉義特殊字符。 支持以下轉義序列: \t, \b, \n, \r,\', \", \\\$; 要編碼任何其他字符,請使用Unicode轉義序列語法:'\uFF00'

可以將一個字符顯式轉換爲一個Int類型數字:

fun decimalDigitValue(c: Char): Int {
    if (c !in '0'..'9')
        throw IllegalArgumentException("Out of range")
    return c.toInt() - '0'.toInt() // Explicit conversions to numbers
}

像數字一樣,當需要可空引用時,字符將被包裝。標識不能被裝箱操作所保留。

布爾類型

Boolean類型表示布爾值,並具有兩個值:truefalse

如果需要可空引用,布爾值將可被裝箱。

內置的布爾操作包括:

  • || – 懶分離
  • && – 懶結合
  • ! - 否定

數組

Kotlin中的數組由Array類表示,它有get()set()函數(通過運算符重載約定轉換爲[]),以及size屬性以及其他一些有用的成員函數:

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(),並將數組的元素值傳遞給它,如:arrayOf(1,2,3)創建一個數組[1,2,3]。 或者arrayOfNulls()庫函數可用於創建一個填充空(null)元素的給定大小的數組。

另一個選擇是使用一個工廠函數,它使用數組大小和返回給定其索引的每個數組元素的初始值的函數:

// Creates an Array<String> with values ["0", "1", "4", "9", "16"]
val asc = Array(5, { i -> (i * i).toString() })

如上所述,[]操作代表調用成員函數get()set()

注意:與Java不同,Kotlin中的數組是不變的。 這意味着Kotlin不允許將Array <String>分配給Array <Any>,這樣可以防止可能的運行時故障(但可以使用Array <out Any>),詳細的可參考類型投影。

Kotlin還有專門的類來表示原始類型的數組,沒有裝箱開銷,它們分別是:ByteArray, ShortArray, IntArray等等。

這些類與Array類沒有繼承關係,但它們具有相同的方法和屬性集。它們也有相應的工廠函數:

val x: IntArray = intArrayOf(1, 2, 3)
x[0] = x[1] + x[2]

字符串

字符串由String類型表示。字符串是不可變的。 字符串的元素可以通過索引操作的字符:s[i]來訪問。可以使用for循環迭代字符串:

for (c in str) {
    println(c)
}

字符串字面量

Kotlin有兩種類型的字符串字面值:可以在其中轉義字符的轉義字符串,以及可以包含換行符和任意文本的原始字符串。 轉義的字符串非常像Java字符串:

val s = "Hello, world!\n"

使用反斜槓以常規方式完成轉義。 有關支持的轉義序列的列表,請參閱上述字符

原始字符串由三重引號(""")分隔,不包含轉義,並且可以包含換行符和任何其他字符:

val text = """
    for (c in "foo")
        print(c)
"""

可以使用trimMargin()函數刪除前導空格:

val text = """
    |Tell me and I forget.
    |Teach me and I remember.
    |Involve me and I learn.
    |(Benjamin Franklin)
    """.trimMargin()

默認使用|作邊距前綴,但您可以選擇另一個字符,並將其作爲參數傳遞:trimMargin(">")

字符串模板

字符串可以包含模板表達式,即被評估的代碼片段,並且其結果被連接到字符串中。 模板表達式以美元符號($)開頭以及簡單名稱組成:

val i = 10
val s = "i = $i" // evaluates to "i = 10"

或大括號中的任意表達式:

val s = "abc"
val str = "$s.length is ${s.length}" // evaluates to "abc.length is 3"

原始字符串和轉義字符串內部都支持模板。如果您需要在原始字符串(不支持反斜槓轉義)中表示一個文字$字符,則可以使用以下語法:

val price = """
${'$'}9.99
"""