【修煉內功】[kotlin] 聊一聊泛型的可空性

林舍發表於2018-11-09
本文已收錄【修煉內功】躍遷之路

什麼?泛型本身也可以是nullable?上來就拋這麼個問題實在是不夠友好~

首先回顧,什麼是泛型?Oracle Java Tutorials

Introduced in J2SE 5.0, this long-awaited enhancement to the type system allows a type or method to operate on objects of various types while providing compile-time type safety. It adds compile-time type safety to the Collections Framework and eliminates the drudgery of casting.

泛型的本質是引數化型別,也就是說操作的資料型別被指定為一個引數。簡單來講,泛型就是操作型別的佔位符。

那,為什麼要使用泛型?Oracle Java Tutorials

In a nutshell, generics enable types (classes and interfaces) to be parameters when defining classes, interfaces and methods. Much like the more familiar formal parameters used in method declarations, type parameters provide a way for you to re-use the same code with different inputs. The difference is that the inputs to formal parameters are values, while the inputs to type parameters are types.

泛型的好處是在編譯的時候做型別安全檢查,並且所有的強制轉換都是自動和隱式的,提高程式碼的重用率。

在深入討論泛型的可空性之前,首先看一個簡單的例子 (kotlin中更多泛型的介紹,以及其與java泛型的區別,可以檢視Generics)

fun <T> whoAmI(t: T) {
    val clazz = t::class
    println("I'm $clazz")
}

上面的程式碼是編譯不過的,問題在於
clipboard.png

nullable type 'T'是什麼鬼?OK,我們按照提示,為引數t加上!!強制標識為not-null (關於!!的使用,可以檢視Null Safety)

clipboard.png

WTF~ 嗶~ 卒~

在繼續討論之前,先關注兩個概念,type parametertype argument,在一個函式中,前者是函式引數的型別(型別),如translate(java.lang.String, java.lang.String)中的java.lang.String,而後者則是函式呼叫時傳入的具體值(型別),如translate("Hello You!", "zh-cn")中的Hello Youzh-cn,泛型作為一個佔位符,佔的正是type parameter的位

首先簡單瞭解一下argument的可空性,kotlin中控制函式引數值(類屬性值等)的nullable是透過?符號實現的,預設均為non-nullable,如以下程式碼片段是編譯不過的

clipboard.png

只有指定引數name為nullable,才可以順利編譯

clipboard.png

同樣,對應泛型類,我們也可以指定nullable及non-nullable的type argument

clipboard.png

從上例中可以看到,null在kotlin中的型別為Nothing?(kotlin中一切皆為物件)

更多內容請參考 Null Safety

說了這麼多,到底什麼是泛型的可空性(type argumentnullable)?

上例中,之所以可以將forestA指定為Forest<Tree?>,是因為,每一個nullabletype argument都有一個隱式邊界Any?,即如下兩種類宣告完全等價

// T的隱式邊界為Any?
class Forest<T>

// 顯示指定T的邊界為Any?
class Forest<T : Any?>

// 顯示指定T的邊界為Tree?
class Forest<T : Tree?>

如果將Forest中的泛型強制指定為non-nullable會發生什麼

clipboard.png

什麼?不能將nullable的Tree?應用到Forest類了!這是因為Forest類的定義中,我們強制將泛型的邊界指定為了non-nullable的Tree

所以,回到文章的開頭,函式whoAmI的錯誤資訊nullable type 'T'指的是哪個鬼?泛型T的預設邊界為Any?,即T : Any?,所以,我們只需要顯示指定T為non-nullable即可

clipboard.png

至此,對於nullablenon-nullabletype parametertype argument是否有所瞭解?


訂閱號

相關文章