在 Kotlin 中使用 `?` 进行类似 Rust 的错误处理,这可能吗?
Rust-like error handling in Kotlin using `?`, is it possible?
下面的代码有几个可能的失败。例如,width
可能为空,或者 r
可能为假。在所有情况下,我应该 return 一个 result.error()
或类似的东西。
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
if (call.method == "getPlatformVersion") {
result.success("Android ${android.os.Build.VERSION.RELEASE}")
} else if (call.method=="registerTexture") {
val entry: TextureRegistry.SurfaceTextureEntry = texture_registry.createSurfaceTexture();
val surfaceTexture = entry.surfaceTexture();
//TODO: return non-sucess when no width and height passed
val width: Int = call.argument("width")!!
val height: Int = call.argument("height")!!
surfaceTexture.setDefaultBufferSize(width, height)
val response = HashMap<String, Long>()
RendererPlugin.surfaceTextureMap.put(entry, surfaceTexture)
val r = RendererPlugin.registerSurfaceTextureNativeHandler(entry.id(), surfaceTexture)
if (!r) {
Log.d(LOG_TAG, "attention: failed result from registerSurfaceTextureNativeHandler")
}
response.put("textureId", entry.id())
result.success(response)
}
}
在 Rust 上,我将所有这些都放入一个闭包中,结果为 Result<(), Error>
,然后在 onMethodCall
中执行闭包,如果出现错误,我会 return 一个错误。此外,闭包将充满以 ?
结尾的调用,因此它会自动 return 将具有 From<>
实现的错误转换为 Error
.
如何在 Kotlin 中高效地执行此操作?有没有办法做一个闭包,也很容易在这个闭包中 return 成功或错误,然后根据这个结果我调用 result.sucess
或 result.error
?
希望对您有所帮助。
注意:我假设 result.success()
接受 Any
因为你 return String
或 HashMap
作为参数,但是 kotlin.Result
没有几个通用的成功参数。您可以使用 kotlin.Pair<A, B>
作为 kotlin.Result
的成功类型:D
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
val finalResult: kotlin.Result<Any> = call.run {
if (method == "getPlatformVersion") kotlin.Result.success("Android ${android.os.Build.VERSION.RELEASE}")
else if (method == "registerTexture") {
val entry: TextureRegistry.SurfaceTextureEntry = texture_registry.createSurfaceTexture();
val surfaceTexture = entry.surfaceTexture();
val width = argument("width") ?: return@run kotin.Result.failure(IllegalArgumentException("width is null"))
val height = argument("height") ?: return@run kotlin.Result.failure(IllegalArgumentException("height is null"))
surfaceTexture.setDefaultBufferSize(width, height)
val response = HashMap<String, Long>()
RendererPlugin.surfaceTextureMap.put(entry, surfaceTexture)
val r = RendererPlugin.registerSurfaceTextureNativeHandler(entry.id(), surfaceTexture)
if (!r) return@run kotlin.Result.failure(IllegalArgumentException("r is false"))
response.put("textureId", entry.id())
kotlin.Result.success(response)
}
else kotlin.Result.failure(IllegalStateException("undefined call.method"))
}
with (finalResult) {
onSuccess(result::success)
onFailure(result::fail)
}
}
有一个 runCatching
函数可以调用任何东西。在以下 lambda 闭包中,您调用它的对象是“this
”。您可以 return 成功的东西,或者失败的东西。然后你可以将这个结果解压到你的 Result
对象中。 error()
、require()
和 check()
是在特定条件下抛出异常而不会中断代码流的有用方法。
要return 来自 lambda 外壳的东西,您可以使用 return@nameOfFunctionLambdaIsPassedTo
手动完成,或者让 lambda 的最后一个表达式成为 return 值。 when
表达式可以用作 lambda 的最后(唯一)表达式,因此 when
每个分支中的最后一件事是成功的 returned 结果(或抛出的错误).
这是一个例子:
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
call.runCatching {
when(method) {
"getPlatformVersion" -> "Android ${android.os.Build.VERSION.RELEASE}"
"registerTexture" -> {
val entry = texture_registry.createSurfaceTexture()
val surfaceTexture = entry.surfaceTexture()
val width: Int = argument("width") ?: error("no width passed")
val height: Int = argument("height") ?: error("no height passed")
surfaceTexture.setDefaultBufferSize(width, height)
RendererPlugin.surfaceTextureMap.put(entry, surfaceTexture)
check(RendererPlugin.registerSurfaceTextureNativeHandler(entry.id(), surfaceTexture)) {
"attention: failed result from registerSurfaceTextureNativeHandler"
}
mapOf("textureId", entry.id())
}
else -> error("unsupported method name: $method")
}
}
.onSuccess(result::success)
.onFailure(result::failure)
}
如果您想避免调用 onSuccess
/onFailure
,您可以创建一个可以重复使用的通用扩展函数,如下所示:
inline fun MethodCall.runForResult(result: Result, block: MethodCall.() -> Any) {
runCatching(block).onSuccess(result::success).onFailure(result::failure)
}
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
call.runForResult(result) {
when(method) {
"getPlatformVersion" -> "Android ${android.os.Build.VERSION.RELEASE}"
"registerTexture" -> {
val entry = texture_registry.createSurfaceTexture()
val surfaceTexture = entry.surfaceTexture()
val width: Int = argument("width") ?: error("no width passed")
val height: Int = argument("height") ?: error("no height passed")
surfaceTexture.setDefaultBufferSize(width, height)
RendererPlugin.surfaceTextureMap.put(entry, surfaceTexture)
check(RendererPlugin.registerSurfaceTextureNativeHandler(entry.id(), surfaceTexture)) {
"attention: failed result from registerSurfaceTextureNativeHandler"
}
mapOf("textureId", entry.id())
}
else -> error("unsupported method name: $method")
}
}
}
下面的代码有几个可能的失败。例如,width
可能为空,或者 r
可能为假。在所有情况下,我应该 return 一个 result.error()
或类似的东西。
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
if (call.method == "getPlatformVersion") {
result.success("Android ${android.os.Build.VERSION.RELEASE}")
} else if (call.method=="registerTexture") {
val entry: TextureRegistry.SurfaceTextureEntry = texture_registry.createSurfaceTexture();
val surfaceTexture = entry.surfaceTexture();
//TODO: return non-sucess when no width and height passed
val width: Int = call.argument("width")!!
val height: Int = call.argument("height")!!
surfaceTexture.setDefaultBufferSize(width, height)
val response = HashMap<String, Long>()
RendererPlugin.surfaceTextureMap.put(entry, surfaceTexture)
val r = RendererPlugin.registerSurfaceTextureNativeHandler(entry.id(), surfaceTexture)
if (!r) {
Log.d(LOG_TAG, "attention: failed result from registerSurfaceTextureNativeHandler")
}
response.put("textureId", entry.id())
result.success(response)
}
}
在 Rust 上,我将所有这些都放入一个闭包中,结果为 Result<(), Error>
,然后在 onMethodCall
中执行闭包,如果出现错误,我会 return 一个错误。此外,闭包将充满以 ?
结尾的调用,因此它会自动 return 将具有 From<>
实现的错误转换为 Error
.
如何在 Kotlin 中高效地执行此操作?有没有办法做一个闭包,也很容易在这个闭包中 return 成功或错误,然后根据这个结果我调用 result.sucess
或 result.error
?
希望对您有所帮助。
注意:我假设 result.success()
接受 Any
因为你 return String
或 HashMap
作为参数,但是 kotlin.Result
没有几个通用的成功参数。您可以使用 kotlin.Pair<A, B>
作为 kotlin.Result
的成功类型:D
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
val finalResult: kotlin.Result<Any> = call.run {
if (method == "getPlatformVersion") kotlin.Result.success("Android ${android.os.Build.VERSION.RELEASE}")
else if (method == "registerTexture") {
val entry: TextureRegistry.SurfaceTextureEntry = texture_registry.createSurfaceTexture();
val surfaceTexture = entry.surfaceTexture();
val width = argument("width") ?: return@run kotin.Result.failure(IllegalArgumentException("width is null"))
val height = argument("height") ?: return@run kotlin.Result.failure(IllegalArgumentException("height is null"))
surfaceTexture.setDefaultBufferSize(width, height)
val response = HashMap<String, Long>()
RendererPlugin.surfaceTextureMap.put(entry, surfaceTexture)
val r = RendererPlugin.registerSurfaceTextureNativeHandler(entry.id(), surfaceTexture)
if (!r) return@run kotlin.Result.failure(IllegalArgumentException("r is false"))
response.put("textureId", entry.id())
kotlin.Result.success(response)
}
else kotlin.Result.failure(IllegalStateException("undefined call.method"))
}
with (finalResult) {
onSuccess(result::success)
onFailure(result::fail)
}
}
有一个 runCatching
函数可以调用任何东西。在以下 lambda 闭包中,您调用它的对象是“this
”。您可以 return 成功的东西,或者失败的东西。然后你可以将这个结果解压到你的 Result
对象中。 error()
、require()
和 check()
是在特定条件下抛出异常而不会中断代码流的有用方法。
要return 来自 lambda 外壳的东西,您可以使用 return@nameOfFunctionLambdaIsPassedTo
手动完成,或者让 lambda 的最后一个表达式成为 return 值。 when
表达式可以用作 lambda 的最后(唯一)表达式,因此 when
每个分支中的最后一件事是成功的 returned 结果(或抛出的错误).
这是一个例子:
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
call.runCatching {
when(method) {
"getPlatformVersion" -> "Android ${android.os.Build.VERSION.RELEASE}"
"registerTexture" -> {
val entry = texture_registry.createSurfaceTexture()
val surfaceTexture = entry.surfaceTexture()
val width: Int = argument("width") ?: error("no width passed")
val height: Int = argument("height") ?: error("no height passed")
surfaceTexture.setDefaultBufferSize(width, height)
RendererPlugin.surfaceTextureMap.put(entry, surfaceTexture)
check(RendererPlugin.registerSurfaceTextureNativeHandler(entry.id(), surfaceTexture)) {
"attention: failed result from registerSurfaceTextureNativeHandler"
}
mapOf("textureId", entry.id())
}
else -> error("unsupported method name: $method")
}
}
.onSuccess(result::success)
.onFailure(result::failure)
}
如果您想避免调用 onSuccess
/onFailure
,您可以创建一个可以重复使用的通用扩展函数,如下所示:
inline fun MethodCall.runForResult(result: Result, block: MethodCall.() -> Any) {
runCatching(block).onSuccess(result::success).onFailure(result::failure)
}
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
call.runForResult(result) {
when(method) {
"getPlatformVersion" -> "Android ${android.os.Build.VERSION.RELEASE}"
"registerTexture" -> {
val entry = texture_registry.createSurfaceTexture()
val surfaceTexture = entry.surfaceTexture()
val width: Int = argument("width") ?: error("no width passed")
val height: Int = argument("height") ?: error("no height passed")
surfaceTexture.setDefaultBufferSize(width, height)
RendererPlugin.surfaceTextureMap.put(entry, surfaceTexture)
check(RendererPlugin.registerSurfaceTextureNativeHandler(entry.id(), surfaceTexture)) {
"attention: failed result from registerSurfaceTextureNativeHandler"
}
mapOf("textureId", entry.id())
}
else -> error("unsupported method name: $method")
}
}
}