Kotlin 運算子與運算表達式 (Operators)

運算子 (Operators) 是程式語言中用來對變數或數值進行操作的符號。例如 + 是加法運算子,* 是乘法運算子。

Kotlin 支援豐富的運算子,包括常見的算術運算、邏輯運算,以及 Kotlin 特有的範圍運算子和空值安全運算子。本章節將帶你詳細了解這些運算子的用法。

Kotlin 的運算子大多對應到特定的成員函式 (Member Function) 或擴充函式 (Extension Function)。例如 a + b 在底層其實是呼叫了 a.plus(b)。這稱為運算子重載 (Operator Overloading)

算術運算子 (Arithmetic Operators)

用於執行基本的數學運算。

運算子說明程式範例對應函式
+加法10 + 5 (結果 15)plus()
-減法10 - 5 (結果 5)minus()
*乘法10 * 5 (結果 50)times()
/除法10 / 5 (結果 2)div()
%取餘數 (Modulus)10 % 3 (結果 1)rem()
fun main() {
    val a = 10
    val b = 3

    println(a + b)  // 13
    println(a - b)  // 7
    println(a * b)  // 30
    
    // 注意:整數除法會無條件捨去小數點
    println(a / b)  // 3 (不是 3.333...)
    
    println(a % b)  // 1 (10 除以 3 的餘數)
}
如果希望除法保留小數點,其中一個運算元必須是浮點數 (如 DoubleFloat)。例如:10.0 / 3 結果會是 3.3333333333333335

指派運算子 (Assignment Operators)

用於將值賦予給變數,通常結合了算術運算。

運算子說明範例等同於
=賦值x = 5x = 5
+=加後賦值x += 5x = x + 5
-=減後賦值x -= 5x = x - 5
*=乘後賦值x *= 5x = x * 5
/=除後賦值x /= 5x = x / 5
%=取餘數後賦值x %= 5x = x % 5
fun main() {
    var num = 10
    num += 5  // num 變為 15
    num *= 2  // num 變為 30
    println(num)
}

一元運算子 (Unary Operators)

只需要一個運算元的操作。

運算子說明範例對應函式
+正號 (通常省略)+5unaryPlus()
-負號 (變號)-5unaryMinus()
++遞增++aa++inc()
--遞減--aa--dec()
!邏輯「非」 (Not)!flagnot()

遞增與遞減 (Prefix vs Postfix)

++-- 放在變數前面 (Prefix) 和後面 (Postfix) 有重要的差別:

  • 前綴 (++a):先將 a 加 1,然後回傳加完後的值。
  • 後綴 (a++):先回傳 a 原本的值,然後才將 a 加 1。
fun main() {
    var a = 5
    var b = 5

    println(++a) // 輸出 6 (先加 1,再印出)
    println(b++) // 輸出 5 (先印出原本的 5,再加 1)
    
    println(a)   // 6
    println(b)   // 6 (此時 b 已經變成 6 了)
}

比較運算子 (Comparison Operators)

用於比較兩個值,結果永遠是 Boolean (truefalse)。

運算子說明
==相等 (Structural Equality)
!=不相等
<小於
>大於
<=小於等於
>=大於等於

相等性比較:== vs ===

Kotlin 有兩種相等的概念:

  1. 結構相等 (Structural Equality) ==: 檢查兩個物件的內容是否相同 (底層呼叫 equals())。這是我們最常用的比較方式。

  2. 參考相等 (Referential Equality) ===: 檢查兩個變數是否指向記憶體中的同一個物件

fun main() {
    val str1 = "Hello"
    val str2 = "Hello"
    val str3 = str1

    // String 若內容相同,編譯器通常會優化指向同一記憶體,但為了演示 New 一個
    val obj1 = Integer(100) 
    val obj2 = Integer(100)

    println(obj1 == obj2)  // true (數值內容都是 100)
    println(obj1 === obj2) // false (它們是兩個不同的物件實體)
    
    println(obj1 != obj2)  // false
    println(obj1 !== obj2) // true
}

邏輯運算子 (Logical Operators)

用於布林值 (Boolean) 的邏輯判斷。

運算子說明邏輯
&&且 (AND)兩邊都為 true 時,結果才為 true
||或 (OR)只要有一邊為 true,結果就為 true
!非 (NOT)truefalsefalsetrue

短路求值 (Short-circuit evaluation)

  • 對於 &&:如果左邊為 false,則不用計算右邊,結果一定為 false
  • 對於 ||:如果左邊為 true,則不用計算右邊,結果一定為 true

這在檢查 null 或避免錯誤時很有用:

fun main() {
    val str: String? = null
    
    // 因為 str != null 為 false,後面的 str.length > 0 根本不會執行
    // 這樣就避免了對 null 呼叫 .length 導致的 Crash
    if (str != null && str.length > 0) {
        println("String is valid")
    } else {
        println("String is null or empty")
    }
}

位元運算子 (Bitwise Operations)

Kotlin 沒有像 C 或 Java 那樣的 <<, >>, &, | 符號運算子,而是使用中綴函式 (Infix Functions) 來處理位元運算。只有 IntLong 可以進行位元運算。

函式對應符號 (其他語言)說明
shl(bits)<<左移 (Signed shift left)
shr(bits)>>右移 (Signed shift right)
ushr(bits)>>>無號右移 (Unsigned shift right)
and(bits)&位元 And
or(bits)|位元 Or
xor(bits)^位元 Xor (互斥或)
inv()~位元反轉 (Invert)
fun main() {
    val x = 0b0101 // 十進位 5
    val y = 0b0011 // 十進位 3

    println(x and y) // 0b0001 (1)
    println(x or y)  // 0b0111 (7)
    println(x xor y) // 0b0110 (6)
    
    val z = 1
    println(z shl 2) // 4 (二進位 1 變為 100)
}

範圍與檢查運算子 (Range & Check)

Kotlin 提供了一些特殊的運算子來處理範圍和型別檢查。

運算子說明範例
..建立範圍 (Range)1..10 (1 到 10)
in檢查是否在範圍內x in 1..10
!in檢查是否不在範圍內x !in 1..10
fun main() {
    val item = 5
    if (item in 1..10) {
        println("$item 在 1 到 10 之間")
    }

    // 也可以用於集合
    val list = listOf("A", "B", "C")
    if ("A" in list) {
        println("A 在清單中")
    }
}

另外還有 is!is 用於檢查型別,詳細請參考 型別檢查與轉型

索引存取運算子 (Indexed Access Operator)

使用常看到的方括號 [] 來存取陣列或 Map 的元素。這其實對應到 get()set() 函式。

  • a[i] 等同於 a.get(i)
  • a[i] = b 等同於 a.set(i, b)
fun main() {
    val array = arrayOf(1, 2, 3)
    
    // 讀取
    println(array[0]) // 1
    
    // 寫入
    array[0] = 100
    println(array[0]) // 100
    
    val map = mutableMapOf("name" to "Mike", "age" to "18")
    map["name"] = "John" // 更新 Map
    println(map["name"])
}

其他重要運算子

還有一些 Kotlin 特有的運算子,會在其專屬章節詳細介紹:

  • 空值安全運算子 (?., ?:, !!):請參考 Null Safety
  • 類別相關 (::):用於 Reflection 或 Function Reference。

運算子優先順序 (Precedence)

Kotlin 的運算子優先順序與大多數 C-style 語言 (Java, C++, JavaScript) 類似。 大原則是:

  1. *, /, % 優先於 +, -
  2. && 優先於 ||

如果不確定順序,或者為了讓程式碼更易讀,建議永遠使用括號 () 來明確指定運算順序

val result = (10 + 5) * 2 // 明確先做加法,結果 30
val result2 = 10 + 5 * 2  // 先做乘法,結果 20