iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 4
0
Mobile Development

30天,從0開始用Kotlin寫APP系列 第 4

Day 04 | 變量、類型推斷以及字串模版

今天終於要開始進入 Kotlin 語法的世界了!
請讀者先打開 Kotlin Playground或是其他能夠編譯 Kotlin 的 IDE

變量 Variable

在 Kotlin 文件中有這麼一段話

In Kotlin, everything is an object in the sense that we can call member functions and properties on any variable.
[color=orange]

簡單翻譯就是,任何東西在 Kotlin 中都是物件(Object) ,因此開發者可對任何變量調用其中的成員函式與屬性。換句話說,任何變量都是根據引用的物件(Numbers, Characters and Booleans... )來操作,因此在宣告變數時需要提供

變量 變數名稱:物件 = 初始值
[color=orange]

Example:

val a: Int = 1   // 正確,即宣告 a 為 Int,且初始值為 1
val b: Int = "1" // 錯誤,已經宣告 b 為 Int,就不能初始值給 String

而 Kotlin 中的變量又可以分為 val 與 var 兩種,這有什麼區別呢?

  • val : Read-Only ,在初始宣告之後,就不能再重新附值,相當於 Java 中的 final,雖然你不能對他重新附值,但可以去改變其中的屬性
  • var : Read-And-Write ,可以在初始宣告後重新對他附值

Example:

val a: Int = 1 // 宣告 a 是 1 ,並且變量是 val ,因此只能 Read-Only
a = 2          // 若重新對 a 附值,會跳 Error 並且拒絕
println(a)

var b: Int = 1 // 宣告 b 是 1,並且變量是 var,因此可 Read-And-Write
b = 2          //若重新對 b 附值,則 b 會是 2
println(b)

我會推荐寫程式時,變數宣告上盡可能使用 val ,因為 val 不可重新附值,因此能夠更簡單的預測變數行為以及在多線程與多協程中會更加安全


類型推斷 Type Inference

在寫 Java 時,會需要在宣告就告訴 Compiler 這個變數是 int, String, Boolean... 中哪一種型態,但在 Kotlin 中你不需要再告訴 Compiler , Compiler 會根據你提供的初始值決定這個變數應該要是什麼型態

Example:

fun main() {
    val a = 1              // Compiler 會根據初始值決定變數型態
    typeInference(a)       // 因為 1 是 Int,所以丟 a 進去,會印出 "Is Int"
    
    val b = 1L             // L 代表 Long
    typeInference(b)       // 因為 1L 是 Long,所以丟 b 進去,會印出 "Is Long"
    
    val c = listOf(1,2,3)  // 包括 List 也可以做類型推斷
    typeInference(c)       // 印出 "Is List"
}

fun typeInference(input: Any) {
    when (input) {
        is Int -> println("Is Int")
        is Long -> println("Is Long")
        is String -> println("Is String")
        is List<*> -> print("Is List")
        else -> println("Not sure")
    }
}

另外,不知道各位有沒有寫 Python 的經驗,在 Python 裏面你可以對變數付予不同類型的值,所以常常在程式中加入類型推斷的判斷,雖然這樣宣告真的很爽,但有時候 Run Time 才會發現有 Bug,心情就有點不愉快了

Example:

a = 1
print(a) # Output: 1

a = "Hello World!"
print(a) # Output: Hello World!

a = a + 1
print(a) # Output: TypeError: Can't convert 'int' object to str implicitly

但在 Kotlin 中,雖然會自己做類型推斷,但要是已經推斷後的變數就不能透過給不同類型變數的方式去改變他的類型了,因此也不會碰到上述的情況

Example:

fun main() {
    var a = 1 // 此時 a 是 Int
    a = 2 // 正確, a 會是 2
    a = "Hello World!" // 錯誤, IDE 會在 run time 前告訴你不可以這樣用,必須要轉型才能這樣用
}

雖然 Type Inference 可以簡化 code ,然而我最近在開發上常常會督促自己在宣告時就告訴他型態,比較偏向 Java 那邊的用法,原因有兩個

  • 第一個原因和之後會提到的 Null Safty 以及我自己的個性有關。因為用類型推斷,如果近來的值是 nullable ,那這個變數就會被推斷為可以接受 null ,那依照我粗枝大葉的個性,可能會不小心把 null 在程式裏面傳來傳去還不知道,最後反而會噴 NullPointException ,那這和 Kotlin 設計的本意衝突,所以我會近可能在宣告時就設定這個變數是哪種 type 且能不能接受 null
  • 第二個原因是和可讀性有關。在 github 上面爬別人 code 時,我會因為他沒有設定類別,因此在某些狀況下需要去猜說這個可能是哪種型態,因此為了可讀性,我還是會順手把型態加上去


字串模版 String Template

字串模版也是 Java 和 Kotlin 之間其中一個差異,在 Java 中是使用 "+" 做字串的連接,但在 Kotlin 中可以使用 "$變數" 將字串放入令一個字串中

Example:

// Java 中字串的用法
String a = "java";
String message = "message is" + a;
println(message) // Output: message is java
// Kotlin 中字串的用法
val a: String = "kotlin";
val message: String = "message is $a" 
println(message) // Output: message is kotlin

而 Kotlin 字串模版真正的強大當然不只有這樣,你可以把任何型態的變數丟進去另一個字串中,這樣的好處就是可以省下自己寫轉型, Code 相對而言也會乾淨許多

Example:

val a: Int = 1
val message: String = "message is $a"
println(message) // Output: message is 1

而還有更進階的用法是 "${運算式或判斷式}",是不是非常的方便呢~

Example:

val a: Int = 1
val message = "message = ${a + 1}"
println(message) // Output: message is 2

val b: Int = -1
val message = "$b is ${if(b > 0) "positive" else "not positive"}"
println(message) // Output: -1 is not positive

val c: Int = -10
val message = "$c is ${if (c > 0) "positive" else if (c < 0) "negative and ${if (c % 2 == 0) "even" else "odd"}" else "zero"}"
println(message) // Output: -10 is negative and even


結語

今天介紹了 Kotlin 中的變量、類型推斷、以及字串模版如何使用,這些都算是學 Kotlin 時,基礎中的基礎,尤其字串模版剛開始會很常忘記有這個東西,但習慣之後,真的可以解決掉很多的轉型問題喔。

如果對文章有任何問題或建議,都歡迎留言指教。

Reference


上一篇
Day 03 | Kotlin 起手式: IDE 怎麼選?
下一篇
Day 05 | Kotlin 中的條件式、循環式與跳轉方法
系列文
30天,從0開始用Kotlin寫APP30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言