分類彙整: JVM Language

Kotlin’s Nullable vs. Swift’s Optional

最近在學 Kotlin 與重學那個學過但沒有學會過的 Swift,發現 Kotlin 的 nullable 與 Swift 的 Optional 非常像,大概有 87 分像吧 (不能再低了)? 所以我做了個對照表:

補充說明:

  1. 使用 ?.as? 運算子時,傳回值的型態一樣會是 nullable (Kotlin) / Optional (Swift),所以對傳回值的後續處理一樣要用 nullable (Kotlin) / Optional (Swift) 的方式對待之。 (心法:只要傳回值有可能出現空值 ( null / nil ),那個傳回值就會是一個 nullable / Optional 。)
  2. Swift Optional 的驚嘆號 ( ! ) 表示直接把 Optional 變數解包並當成有值去對待,所以當變數是空值 (nil) 的時候,對空值調用方法 (或者說:發送訊息) 時當然會當掉,因為空值無法響應那個方法。例如這行程式:str!.uppercased(),當 str 裡是一個 String 的時候,對它調用 .uppercased() 方法是沒問題的,可是當 str 裡是 nil 的時候,這時就會出錯了,因為 nil 沒有 .uppercased() 這個方法,所以會當掉。Kotlin 的 !! 符號是非空斷言 (Not-Null Assertion),告訴編譯器這個地方出現的值不會是 null,所以編譯器會把它當成非空型態去處理,但是,如果這個值不幸是 null 的話,就會拋出一個例外。
  3. Kotlin nullable 與 Swift Optional 不一樣的地方在於:Kotlin nullable 不是一個實際的 Type,例如這行 Kotlin 程式:var str : String? 表示 str 實際上的 Type 會有兩種情況:String 或 null,所以 str 變數的值有可能是一個字串,也有可能是一個空值。但是在 Swift 裡,這行程式:var str : String? 表示 str 的 Type 是一個 Optional,str 變數的值就是一個 Optional,只是這個 Optional 裡的內容可能是一個字串,也可能是一個 nil。也就是説:當一個變數的值可能出現空值時,Swift 用 Optional 去封裝那個變數;但在 Kotlin 裡,把變數宣告成 nullable 的型態時,只是在告訴編譯器,這個變數有可能出現空值 (所以這個變數的 Type 實際上可能會出現兩種情況),然後編譯器就會對這個變數做可空型態的檢查,確保程式碼裡有把出現空值的情況考慮進去。

在 Raspberry Pi 上安裝 Groovy

打開終端機,用 apt 指令安裝 OpenJDK 8 與 Groovy:

$ sudo apt install openjdk-8-jdk groovy

然後,我們試試是否可執行 groovy:

$ groovy -v
groovy: JAVA_HOME is not defined correctly, can not execute: /usr/lib/jvm/default-java/bin/java

會顯示「groovy: JAVA_HOME is not defined correctly, can not execute: /usr/lib/jvm/default-java/bin/java」這個訊息。

我們先切換到 /usr/lib/jvm 目錄下查看一下:

$ cd /usr/lib/jvm
$ ls -l
lrwxrwxrwx 1 root root   21  6月 17 02:24 java-1.11.0-openjdk-armhf -> java-11-openjdk-armhf
drwxr-xr-x 9 root root 4096  7月  8 01:20 java-11-openjdk-armhf
lrwxrwxrwx 1 root root   20  3月 29 21:54 java-1.8.0-openjdk-armhf -> java-8-openjdk-armhf
drwxr-xr-x 7 root root 4096  8月  2 13:52 java-8-openjdk-armhf
drwxr-xr-x 9 root root 4096  3月 14  2018 jdk-8-oracle-arm32-vfp-hflt

然後幫 java-8-openjdk-armhf/ 做一個名為 default-java 的 symlink:

$ sudo ln -s java-8-openjdk-armhf/ default-java
$ ls -l
lrwxrwxrwx 1 root root   21  8月  2 14:05 default-java -> java-8-openjdk-armhf/
lrwxrwxrwx 1 root root   21  6月 17 02:24 java-1.11.0-openjdk-armhf -> java-11-openjdk-armhf
drwxr-xr-x 9 root root 4096  7月  8 01:20 java-11-openjdk-armhf
lrwxrwxrwx 1 root root   20  3月 29 21:54 java-1.8.0-openjdk-armhf -> java-8-openjdk-armhf
drwxr-xr-x 7 root root 4096  8月  2 13:52 java-8-openjdk-armhf
drwxr-xr-x 9 root root 4096  3月 14  2018 jdk-8-oracle-arm32-vfp-hflt

然後再執行 groovy 試試看:

$ groovy -v
Groovy Version: 2.4.16 JVM: 1.8.0_212 Vendor: Oracle Corporation OS: Linux

寫個程式測試看看:

$ cd ~
$ vim hello.groovy
def hello(name) {
    println("Hi, " + name)
} 
hello("Pi")

執行程式:

$ groovy hello.groovy
Hi, Pi