我們設計了一款分散式菜單應用,不需要個人去關註公眾號或下載小程式,服務員會提供幾個點單的平板,連接店鋪網路,區域網內通信,這樣大家點單、查看訂單詳情等都不受網路限制。 ...
問題起因
runBlocking的context參數有預設值。但是在Android Studio中查看源代碼,發現源代碼中定義如下:
@Throws(InterruptedException::class)
public actual fun <T> runBlocking(context: CoroutineContext, block: suspend CoroutineScope.() -> T): T
這就很奇怪了。因為doc中明明註釋稱context參數具有預設值,而且官方文檔給出的簽名如下:
expect fun <T> runBlocking(context: CoroutineContext = EmptyCoroutineContext, block: suspend CoroutineScope.() -> T): T
並且Kotlin在Github倉庫上的源代碼也確實與IDE中一致。
而且實際調試時可以發現確實傳入了預設參數。那麼到底是怎麼回事呢?
真相
經過了反編譯、查看文檔與倉庫多次對照後,終於發現問題所在:
問題的關鍵在於expect
和actual
。初學者(比如我)可能會簡單地不怎麼註意函數簽名的這一部分,然而正是這裡造成了預設參數在源代碼中令人困惑的現象!
由於expect定義處已經給出了預設參數,因此當調用到actual函數時,確實可以起到傳入預設參數的作用。然而,令人十分困惑的是,在IDE中查找函數位置只能溯源到actual的函數而不是expect部分,因此很可能產生誤解。
吃一塹長一智,以後再遇到類似地情況,請註意方法簽名是否有actual!預設參數可能定義在expect部分中!另外,優先查看官方文檔,IDE溯源代碼可能產生誤解。