如何在 Kotlin 中实现 main/fallback 函数模式?

问题描述 投票:0回答:1

我想创建一个尝试调用主函数的函数。如果可以,则将该函数的结果返回到外部。但如果失败 - 调用另一个函数(后备函数)并将其结果返回到外部。如果两者都失败 - 应传播第二个函数的异常。

我已经创建了打赏功能:

  fun<T> callWithFallback(
        main: () -> T,
        fallback: () -> T
    ): T = try {
        main()
    } catch (e: Exception) {
        logger.warn(e) { "main call failed: ${e.message}" }
        if (/*some condition*/) {
            try {
                fallback()
            } catch (e: LDAPException) {
                logger.warn(e) { "Repeated call failed: ${e.message}" }
                throw e
            }
        }
        throw e
    }

如果 main 失败 -

fallback()
被调用,但即使成功 - 也会抛出异常(最后一个
throw e
被调用)

我尝试添加

return

  fun<T> callWithFallback(
        main: () -> T,
        fallback: () -> T
    ): T = try {
        main()
    } catch (e: Exception) {
        logger.warn(e) { "main call failed: ${e.message}" }
        if (/*some condition*/) {
            try {
                return fallback()
            } catch (e: LDAPException) {
                logger.warn(e) { "Repeated call failed: ${e.message}" }
                throw e
            }
        }
        throw e
    }

但是会导致编译错误。

我该如何修复它?

kotlin lambda fallback
1个回答
0
投票

您当前实现的问题来自第一个

if
子句中没有
else
catch
语句:

  1. 要了解从 catch 中返回什么,Kotlin 编译器会查看它包含的最后一条语句。在这里,它是

    throw e
    ,而不是包含所需后备的 if。

  2. 由于您的

    if
    没有
    else
    分支,因此它被视为 语句而不是表达式。因此,它无法返回任何内容。您可以通过从
    throw e
    子句中删除
    catch
    来测试此断言。然后,编译器将发出警告,解释它无法从
    catch
    子句返回任何内容:

    如果用作表达式,'if' 必须同时具有主分支和 'else' 分支

要解决您的问题,您可以将函数底部的

throw e
语句移至 else 子句中,如下所示:

  fun<T> callWithFallback(
        main: () -> T,
        fallback: () -> T
    ): T = try {
        main()
    } catch (e: Exception) {
        logger.warn(e) { "main call failed: ${e.message}" }
        if (/*some condition*/) {
            try {
                return fallback()
            } catch (e: LDAPException) {
                logger.warn(e) { "Repeated call failed: ${e.message}" }
                throw e
            }
        } else {
            throw e
        }
    }

这样做会使

if/else
成为
catch
子句中的最新语句,并且由于它是一个表达式(由于 else 分支的存在),因此其结果被视为 catch 的返回值。

© www.soinside.com 2019 - 2024. All rights reserved.