推薦使用 Kotlin 關鍵字 Reified

reified:使抽象的東西更加具體或真實,很是推薦 Android 開發使用這個關鍵字。本文介紹 3 點特別的使用方式以下:java

1. 再也不須要傳參數 clazz

大部分的文章講解 reified 的使用,都有提到這個點,好比咱們定義實現一個擴展函數啓動 Activity,通常都須要傳 Class<T> 參數:安全

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

// Caller
startActivity(context, NewActivity::class.java)
複製代碼

reified 方式

使用 reified,經過添加類型傳遞簡化泛型參數app

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

// Caller
startActivity<NewActivity>(context)
複製代碼

2. 不安全的轉換

Kotlin 中, 使用安全轉換操做符 as?,它能夠在失敗時返回 null。實現以下函數,咱們認爲會安全地獲取數據或返回 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
複製代碼

然而,若是得到的數據不是它指望的類型,這個函數會出現 crash。 所以爲了安全獲取數據,修改以前的函數以下:ui

// 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
複製代碼

這種寫法不太友好,不只在實現函數的方式上,並且還須要傳遞額外的 clazz 參數。spa

reified 方式

使用 reified,簡化泛型參數和保證 as? 類型轉換安全性code

// 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. 不一樣的返回類型函數重載

實現一個函數計算 DP 到像素,並返回一個 Int 或 Float。這種狀況就會想到函數重載,以下所示:開發

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()
}
複製代碼

可是,這將致使編譯時出錯。緣由是,函數重載方式只能根據參數計數和類型不一樣,而不能根據返回類型。get

reified 方式

使用 reified,能夠實現不一樣的返回類型函數重載string

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個例子中,很明顯 reified 使 Kotlin 用起來更加友好。若是還有其餘場景使用 reified 的方法,歡迎分享。

相關文章
相關標籤/搜索