reified
:使抽象的東西更加具體或真實,非常推薦 Android 開發(fā)使用這個關(guān)鍵字。本文介紹 3 點特別的使用方式如下:
1. 不再需要傳參數(shù) clazz
大部分的文章講解 reified
的使用,都有提到這個點,比如我們定義實現(xiàn)一個擴展函數(shù)啟動 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
,通過添加類型傳遞簡化泛型參數(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?
,它可以在失敗時返回 null。實現(xiàn)如下函數(shù),我們認(rèn)為會安全地獲取數(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ù)不是它期望的類型,這個函數(shù)會出現(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àn)函數(shù)的方式上,而且還需要傳遞額外的 clazz
參數(shù)。
reified 方式
使用 reified
,簡化泛型參數(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ù)重載
實現(xiàn)一個函數(shù)計算 DP 到像素,并返回一個 Int 或 Float。這種情況就會想到函數(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ù)重載方式只能根據(jù)參數(shù)計數(shù)和類型不同,而不能根據(jù)返回類型。
reified 方式
使用 reified
,可以實現(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個例子中,很明顯 reified
使 Kotlin 用起來更加友好。如果還有其他場景使用 reified
的方法,歡迎分享。