推薦使用 Kotlin 關(guān)鍵字 Reified

reified:使抽象的東西更加具體或真實(shí),非常推薦 Android 開(kāi)發(fā)使用這個(gè)關(guān)鍵字。本文介紹 3 點(diǎn)特別的使用方式如下:

1. 不再需要傳參數(shù) clazz

大部分的文章講解 reified 的使用,都有提到這個(gè)點(diǎn),比如我們定義實(shí)現(xiàn)一個(gè)擴(kuò)展函數(shù)啟動(dòng) Activity,一般都需要傳 Class<T> 參數(shù):

// Function
private fun <T : Activity> Activity.startActivity(context: Context, clazz: Class<T>) {
    startActivity(Intent(context, clazz))
}

// Caller
startActivity(context, NewActivity::class.java)

reified 方式

使用 reified,通過(guò)添加類型傳遞簡(jiǎn)化泛型參數(shù)

// Function
inline fun <reified T : Activity> Activity.startActivity(context: Context) {
    startActivity(Intent(context, T::class.java))
}

// Caller
startActivity<NewActivity>(context)

2. 不安全的轉(zhuǎn)換

Kotlin 中, 使用安全轉(zhuǎn)換操作符 as?,它可以在失敗時(shí)返回 null。實(shí)現(xiàn)如下函數(shù),我們認(rèn)為會(huì)安全地獲取數(shù)據(jù)或返回 null

// Function
fun <T> Bundle.getDataOrNull(): T? {
    return getSerializable(DATA_KEY) as? T
}

// Caller
val bundle: Bundle? = Bundle()
bundle?.putSerializable(DATA_KEY, "Testing")
val strData: String? = bundle?.getDataOrNull()
val intData: Int? = bundle?.getDataOrNull() // Crash

然而,如果獲得的數(shù)據(jù)不是它期望的類型,這個(gè)函數(shù)會(huì)出現(xiàn) crash。 因此為了安全獲取數(shù)據(jù),修改之前的函數(shù)如下:

// Function
fun <T> Bundle.getDataOrNull(clazz: Class<T>): T? {
    val data = getSerializable(DATA_KEY)
    return if (clazz.isInstance(data)) {
        data as T
    } else {
        null
    }
}

// Caller
val bundle: Bundle? = Bundle()
bundle?.putSerializable(DATA_KEY, "Testing")
val strData: String? = bundle?.getDataOrNull(String::class.java)
val intData: Int? = bundle?.getDataOrNull(String::class.java) // Null

這種寫(xiě)法不太友好,不僅在實(shí)現(xiàn)函數(shù)的方式上,而且還需要傳遞額外的 clazz 參數(shù)。

reified 方式

使用 reified,簡(jiǎn)化泛型參數(shù)和保證 as? 類型轉(zhuǎn)換安全性

// Function
private inline fun <reified T> Bundle.getDataOrNull(): T? {
    return getSerializable(DATA_KEY) as? T
}

// Caller
val bundle: Bundle? = Bundle()
bundle?.putSerializable(DATA_KEY, "Testing")
val strData: String? = bundle?.getDataOrNull()
val intData: Int? = bundle?.getDataOrNull() // Null

3. 不同的返回類型函數(shù)重載

實(shí)現(xiàn)一個(gè)函數(shù)計(jì)算 DP 到像素,并返回一個(gè) Int 或 Float。這種情況就會(huì)想到函數(shù)重載,如下所示:

fun Resources.dpToPx(value: Int): Float {
    return TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP,
        value.toFloat(), displayMetrics)
}

fun Resources.dpToPx(value: Int): Int {
    val floatValue: Float = dpToPx(value)
    return floatValue.toInt()
}

但是,這將導(dǎo)致編譯時(shí)出錯(cuò)。原因是,函數(shù)重載方式只能根據(jù)參數(shù)計(jì)數(shù)和類型不同,而不能根據(jù)返回類型。

reified 方式

使用 reified,可以實(shí)現(xiàn)不同的返回類型函數(shù)重載

inline fun <reified T> Resources.dpToPx(value: Int): T {
    val result = TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP,
        value.toFloat(), displayMetrics)

    return when (T::class) {
        Float::class -> result as T
        Int::class -> result.toInt() as T
        else -> throw IllegalStateException("Type not supported")
    }
}

// Caller
val intValue: Int = resource.dpToPx(64)
val floatValue: Float = resource.dpToPx(64)

從上面的3個(gè)例子中,很明顯 reified 使 Kotlin 用起來(lái)更加友好。如果還有其他場(chǎng)景使用 reified 的方法,歡迎分享。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容