Posted Kotlin
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了写一个 golang 风格的协程扩展相关的知识,希望对你有一定的参考价值。
本文概要
asyncDeferredawaitawaitOrError
launch {
val deferred = ...
val (result, error) = deferred.awaitOrError()
if(error == null){
dealWithResult(result)
} else {
handleError(error)
}
}
需求的诞生
最近因为要定制 BatteryHistorian 这个框架的某些小功能,近距离接触了一些 golang,发现这门语言当中很多可能出异常的函数调用返回两个结果,例如:
bytes, err := ioutil.ReadFile("Hello.go")
if err == nil {
fmt.Print(string(bytes))
} else {
fmt.Print(err)
}
awaittry...catch
try {
val deferred = ...
val result = deferred.await()
dealWithResult(result)
} catch (e: Exception) {
handleError(error)
}
我当时想,如果 Kotlin 的协程能写出 golang 风格的返回,那体验起来还是很不错的。
返回多个值
可是刚要动手写,就要扑街了,Kotlin 不支持多个返回值哎,咋整?
Pair
suspend fun <T> Deferred<T>.awaitOrError(): Pair<T, Throwable> {
return try {
await() to null
} catch (e: Exception) {
null to e
}
}
可空类型的返回值
嗯,看上去不错,只是没法通过编译。为什么呢?返回结果的泛型参数需要定义为可空类型才可以。
suspend fun <T> Deferred<T>.awaitOrError2(): Pair<T?, Throwable?> {
...
}
null
嗯,这回不仅看上去不错,编译也能通过了。不过,用起来却有点儿蛋疼。
val (result, err) = async { ... }.awaitOrError()
resulterrresult
if(err != null) {
if (result != null) {
dealWithResult(result)
}
}
errresult
平台类型
awaitOrErrorresultnull
T!
resultT!
Pair
public class Result<T> {
private T result;
private Throwable error;
public T getResult() {
return result;
}
@Nullable
public Throwable getError() {
return error;
}
public static <T> Result<T> of(Throwable error) {
Result<T> result = new Result<T>();
result.error = error;
return result;
}
public static <T> Result<T> of(T result) {
Result<T> resultJava = new Result<T>();
resultJava.result = result;
return resultJava;
}
}
getErrornullgetResult
Java 数据类与解构
只是,这时候又产生了新的问题,Java 中要怎么定义数据类呢?不是数据类又怎么解构呢?
Result
...
public T component1() {
return result;
}
@Nullable
public Throwable component2() {
return error;
}
...
componentNawaitOrError
suspend fun <T> Deferred<T>.awaitOrError(): Result<T> {
return try {
Result.of(await())
} catch (e: Exception) {
Result.of(e)
}
}
而在调用处,也能按照我们的意愿去检查错误,使用结果,就像文章开头提到的那样:
launch {
val deferred = ...
val (result, error) = deferred.awaitOrError()
if(error == null){
dealWithResult(result)
} else {
handleError(error)
}
}
resultT!
小结
try...catch...
以上是关于写一个 golang 风格的协程扩展的主要内容,如果未能解决你的问题,请参考以下文章