【问题标题】:Why do non-exhaustive when expressions cause compiler error, but when statements don't?为什么当表达式导致编译器错误时不穷尽,但语句不会?
【发布时间】:2021-02-16 22:06:50
【问题描述】:

如果我有一个密封类,例如

sealed class Result {
    object Success: Result()
    object Failure: Result()
}

当语句不是穷举时为什么会编译,而当表达式不能编译时?

        when(getResult()) { //  `when` doesn't show a red squiggly, compiles file
            Result.Success -> {}
        }
        
        val result = when(getResult()) { // <--- when shows a red squiggly, doesn't compile
            Result.Success -> {}
        }

要使其成为 when 语句的编译错误,只需调用详尽的扩展属性:

        when(getResult()) { //  `when` NOW shows a red squiggly            
Result.Success -> {}
        }.exhaustive

我正在观看YouTube: Sealed classes - Kotlin Vocabulary,他们建议使用以下代码来克服这个问题,但我想了解为什么会有差异。这应该有助于我理解为什么以下 Kotlin 通用扩展属性可以解决问题。

val <T> T.exhaustive: T
        get() = this

编辑:感谢 Tenfour04,我知道为什么。我只是不知道为什么这个exhaustive 扩展函数会起作用。

【问题讨论】:

  • 好的,我认为如果它不是详尽无遗的,那将是危险的。但是你不能对 when 表达式说同样的话吗?我们会怎么做?我想这并不危险,只是什么都不会发生
  • 是的,我现在完全理解那部分了(我更新了问题)。但是exhaustive扩展属性添加编译错误的原因是它把when语句变成了表达式?不太清楚那里发生了什么
  • 我已经添加了它,它实际上只是一个 4 分钟的视频,但基本上调用 when(){}.exhaustive 使它成为编译错误。这是一个我不明白/没有解释的巧妙技巧

标签: kotlin


【解决方案1】:

如果结果不是Success,您希望分配什么结果?表达式的重点是评估某事。如果您遇到不计算结果的情况,它就像一个函数,其分支不返回任何内容。

语句不必返回任何内容,因此没有理由强制它返回。这就像一个 if 语句,在 C 或 Java 等语言中没有 else 分支。它适用于您只想在特定条件下执行特定任务的情况。

通过在 when() 的结果上调用某些东西(在本例中为属性),您可以强制编译器将 is 视为表达式而不是语句。一个语句不计算任何东西,所以你不能在它不存在的结果上调用任何东西。

这种强制详尽陈述方式的缺点是它会创建一个属性,该属性将出现在绝对所有内容的自动完成中。你也可以用一个空的作用域函数来标记它,但这看起来有点难看。

when(getResult()) {
    Result.Success -> {}
}.run { }

【讨论】:

  • 不错的技巧,我刚刚使用了run,它比为所有内容定义扩展属性更好,所以我会在我的 PR 中看到它是如何进行的?
【解决方案2】:

Kotlin 1.6 introduced the concept of "sealed when statements",这正是您正在寻找的。 when 关于密封类、枚举和布尔值的语句现在在省略其中一个分支时报告警告。这将成为 Kotlin 1.7 中的错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-13
    • 1970-01-01
    • 2011-06-09
    • 2019-03-12
    • 2021-12-29
    • 2017-04-08
    • 1970-01-01
    相关资源
    最近更新 更多