【问题标题】:Rust-like error handling in Kotlin using `?`, is it possible?使用 `?` 在 Kotlin 中进行类似 Rust 的错误处理,这可能吗?
【发布时间】:2022-06-27 22:28:20
【问题描述】:

下面的代码有几个可能的故障。例如,width 可以为 null,或者r 可以为 false。在所有情况下,我都应该返回 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&lt;(), Error&gt;,然后在 onMethodCall 中执行闭包,如果我遇到错误,我会返回一个错误。此外,闭包将充满以? 结尾的调用,因此它会自动返回具有转换为ErrorFrom&lt;&gt; 实现的错误。

如何在 Kotlin 中有效地做到这一点?有没有办法进行闭包并在此闭包中轻松返回成功或错误,然后根据此结果我调用result.sucessresult.error

【问题讨论】:

标签: kotlin


【解决方案1】:

有一个runCatching 函数可以调用任何东西。在以下 lambda 闭包中,您调用它的对象是“this”。你可以为成功返回一些东西,也可以为失败抛出一些东西。然后您可以将此结果解压缩到您的 Result 对象中。 error()require()check() 是在不中断代码流的情况下在特定条件下抛出的有用方法。

要从 lambda 封装返回某些内容,您可以使用 return@nameOfFunctionLambdaIsPassedTo 手动执行此操作,或者让 lambda 的最后一个表达式作为返回值。 when 表达式可用作 lambda 的最后一个(唯一)表达式,因此 when 的每个分支中的最后一件事是成功返回的结果(或抛出的错误)。

这是一个例子:

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")
        }
    }
}

【讨论】:

    【解决方案2】:

    希望对你有帮助。

    注意:我假设result.success() 接受Any,因为您将StringHashMap 作为参数返回,但kotlin.Result 没有几个通用的成功参数。您可以使用kotlin.Pair&lt;A, B&gt; 作为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 kotlin.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)
        }
    }
    

    【讨论】:

    • 有什么地方可以让我了解return@run 吗?这对我来说毫无意义
    • @GuerlandoOCs,当然 — kotlinlang.org/docs/returns.html
    • 这种情况下真的需要@run吗?
    • 是的。在 lambdas 中不允许裸 return 调用,因为您要从哪个函数返回会不明确。
    • 我收到了Unresolved reference: kotinUnresolved reference: fail
    猜你喜欢
    • 1970-01-01
    • 2020-09-25
    • 1970-01-01
    • 1970-01-01
    • 2012-04-27
    • 1970-01-01
    • 2019-02-27
    • 2011-06-04
    • 2018-05-04
    相关资源
    最近更新 更多