2024五月發(fā)布了Kotlin 2.0,包含了一些新特性比如Enhanced Type Inference
拗小、Multiple Context Receivers
、Better Coroutines
等樱哼,本文研究下這幾個新特性哀九。
1 Improved Type Inference
在Kotlin 1.x版本中剿配,有下面的類型推導寫法:
val listOfPairs = listOf(Pair(1, "One"), Pair(2, "Two"))
val mapFromList = listOfPairs.associate { pair: Pair<Int, String> ->
pair.first to pair.second
}
在Kotlin 2.x版本,就可以使用更好的方式:
val listOfPairs = listOf(1 to "One", 2 to "Two")
val mapFromList = listOfPairs.associate { it.first to it.second }
2 Multiple Context Receivers
在Kotlin 2.x版本阅束,支持了傳入多個context-receivers參數(shù)呼胚,首先我們需要了解下什么是context-receivers。
2.1 了解 context-receivers
比如我們要給String寫個彈Toast的擴展函數(shù)息裸,一般我們會這樣寫:
fun String.toast1(activity: Activity, duration: Int = Toast.LENGTH_LONG) {
Toast.makeText(activity, this, duration).show()
}
借助context-receivers蝇更,我們對上面的函數(shù)進行改造,使之更加簡潔易用:
第一步界牡, 在app/build.gradle.kts添加配置:
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs += arrayOf("-Xcontext-receivers")
}
如果不指定-Xcontext-receivers
簿寂,會有錯誤提示:The feature "context receivers" is experimental and should be enabled explicitly
。
第二步宿亡,新的函數(shù)實現(xiàn):
context(Activity)
fun String.toast2(duration: Int = Toast.LENGTH_LONG) {
Toast.makeText(this@Activity, this, duration).show()
}
這樣常遂,我們可以直接在一個Activity的實例中調(diào)用"hola amigo".toast2(5000)
,而不必再傳Activity參數(shù)了挽荠,是不是比第一個實現(xiàn)方式有那么一點簡潔呢克胳?
context-receivers也挺簡單的,下面介紹下Multiple Context Receivers圈匆。顧名思義漠另,就是支持傳入多個參數(shù)≡咀可以看下面的代碼:
class Database {
fun queryData(): String = "Data from database"
}
class Network {
fun fetchData(): String = "Data from network"
}
context(Database, Network)
fun getData(): String {
val dbData = queryData()
val networkData = fetchData()
return "$dbData - $networkData"
}
fun testWith() {
val database = Database()
val network = Network()
with(database) {
with(network) {
println(getData())
}
}
}
可以看到笆搓,getData
函數(shù)支持傳兩個context-receiver參數(shù),分別是Database和Network纬傲。
3 Improved Coroutines
關(guān)于協(xié)程優(yōu)化满败,我們貼出兩個功能一模一樣的函數(shù)代碼,只是實現(xiàn)方式有點小diff叹括,一段是Kotlin1.x的實現(xiàn)kotlin1_x()
算墨,一段是Kotlin2.x的實現(xiàn)kotlin2_x()
。
suspend fun preBlockTest(): Int {
StarkLog.i("zzh", "abtestclick preblock start 0000")
delay(300)
StarkLog.i("zzh", "abtestclick preblock end 1111")
return -1
}
suspend fun networkRequest(): Int {
StarkLog.i("zzh", "abtestclick network start 0000")
delay(300)
StarkLog.i("zzh", "abtestclick network end 1111")
return 1
}
suspend fun databaseQuery(): String {
StarkLog.i("zzh", "abtestclick database start 0000")
delay(200)
StarkLog.i("zzh", "abtestclick database end 1111")
return "succ"
}
fun kotlin1_x() {
StarkLog.i("zzh", "abtestclick start 0000")
runBlocking {
var d1: Deferred<Int> = async { preBlockTest() }
d1.invokeOnCompletion { handler ->
run {
StarkLog.i("zzh", "abtestclick preblock complete")
}
}
var d1ret = d1.await() // 這里的await會阻塞下面兩個協(xié)程的執(zhí)行汁雷,否則不會阻塞净嘀,
StarkLog.i("zzh", "abtestclick preblock await d1ret=${d1ret}")
// kotlin 1.x
val deferredResults = listOf(
async { networkRequest() },
async { databaseQuery() }
)
val results = deferredResults.awaitAll()
StarkLog.i("zzh", "abtestclick Results: $results")
}
StarkLog.i("zzh", "abtestclick end 1111")
}
fun kotlin2_x() {
StarkLog.i("zzh", "abtestclick start 0000")
runBlocking {
var d1: Deferred<Int> = async { preBlockTest() }
d1.invokeOnCompletion { handler ->
run {
StarkLog.i("zzh", "abtestclick preblock complete")
}
}
var d1ret = d1.await() // 這里的await會阻塞下面兩個協(xié)程的執(zhí)行,否則不會阻塞侠讯,
StarkLog.i("zzh", "abtestclick preblock await d1ret=${d1ret}")
// kotlin 2.x
val results2 = awaitAll(
async { networkRequest() },
async { databaseQuery() }
)
println("Results: $results2")
}
StarkLog.i("zzh", "abtestclick end 1111")
}
參考: