如何为指定Kotlin抽象函数编写Flow风格的扩展函数?
Kotlin扩展函数实现异步回调转Flow
现有Kotlin抽象函数定义如下:
public abstract fun <T : TargetValue> getAverage( metric: StatisticsMetric, interval: DateInterval, timeUnit: TimeUnit, mode: GroupingMode, result: (AsyncResult<kotlin.collections.Map<Info, T>, Error>) -> kotlin.Unit ): kotlin.Unit
其中TargetValueV2继承自TargetValue,需要编写扩展函数,让该函数支持链式调用.asFlow(),返回Flow类型结果,目标调用方式如下:
val flowResult = sdk.getAverage<TargetValueV2>( metric = TIME, interval = DateInterval(startDay, currentDate), timeUnit = DAY, mode = private ).asFlow()
解决方案
1. 封装请求参数的辅助类
首先定义一个辅助类,用来承接getAverage的调用参数,后续扩展函数基于这个类实现Flow转换:
// 替换YourSdkType为定义getAverage的抽象类/接口的实际类型 class GetAverageRequest<T : TargetValue>( internal val sdk: YourSdkType, internal val metric: StatisticsMetric, internal val interval: DateInterval, internal val timeUnit: TimeUnit, internal val mode: GroupingMode )
2. 为SDK添加省略回调的扩展函数
编写扩展函数,让getAverage可以不传result参数,转而返回上面定义的辅助类实例:
fun <T : TargetValue> YourSdkType.getAverage( metric: StatisticsMetric, interval: DateInterval, timeUnit: TimeUnit, mode: GroupingMode ): GetAverageRequest<T> { return GetAverageRequest( sdk = this, metric = metric, interval = interval, timeUnit = timeUnit, mode = mode ) }
3. 实现.asFlow()扩展函数
基于GetAverageRequest编写asFlow扩展,利用callbackFlow将异步回调转换为Flow(需要依赖kotlinx-coroutines-core库):
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow fun <T : TargetValue> GetAverageRequest<T>.asFlow(): Flow<AsyncResult<Map<Info, T>, Error>> { return callbackFlow { sdk.getAverage( metric = metric, interval = interval, timeUnit = timeUnit, mode = mode, result = { asyncResult -> trySend(asyncResult) close() } ) awaitClose() } }
4. 类型推导优化(可选)
如果希望调用时省略显式类型参数,可以使用reified类型参数优化扩展函数:
inline fun <reified T : TargetValue> YourSdkType.getAverage( metric: StatisticsMetric, interval: DateInterval, timeUnit: TimeUnit, mode: GroupingMode ): GetAverageRequest<T> { return GetAverageRequest( sdk = this, metric = metric, interval = interval, timeUnit = timeUnit, mode = mode ) }
此时调用可以简化为:
val flowResult = sdk.getAverage( metric = TIME, interval = DateInterval(startDay, currentDate), timeUnit = DAY, mode = private ).asFlow()
编译器会根据上下文自动推导T为TargetValueV2。
完整调用示例
// 显式指定类型 val flowResult: Flow<AsyncResult<Map<Info, TargetValueV2>, Error>> = sdk.getAverage<TargetValueV2>( metric = TIME, interval = DateInterval(startDay, currentDate), timeUnit = DAY, mode = private ).asFlow() // 自动推导类型(需reified扩展函数支持) val flowResult = sdk.getAverage( metric = TIME, interval = DateInterval(startDay, currentDate), timeUnit = DAY, mode = private ).asFlow()
内容的提问来源于stack exchange,提问作者yozhik
相关产品推荐
相关产品推荐

