为什么Kotlin编译器在有效的IF语句中给出错误?

时间:2019-07-12 23:41:17

标签: android kotlin

在我看来, Kotlin

中出现了一个非常奇怪的编译器错误

因此,我将代码简化为最简单的形式。该代码没有意义,但是尝试了解错误的来源要容易得多。

我已将代码发布到Kotlin Playground中。因此,我不依赖计算机的任何本地配置,并且该错误可以在任何人的任何位置立即重现。

我的完整代码

data class Pilha(
    var funs: ArrayList<Int> 
          = arrayListOf<Int>()  
)

var AP: Array<Pilha> = Array<Pilha>(5) { Pilha() }
fun main() {
    var ele: String=""
    var cl: String = ""
    when (ele) {
        "soul" -> {
            with(AP[0]) {
                when {
                    (cl == "%") -> {
                       if (funs[0]==1)   // <= error in this line
                            cl = "a"
                    }

                    cl == "xU" -> {
           // If I comment this line, the error disappears
                        funs.add(2) 
                    }
                    else -> { cl="b" } // else of inner when
                } // when
            } // with

        } // "soul"
    else->{ cl="c"}  // else of outer when
    } // when
    println("ok")
}   // main

错误消息

if must have both main and 'else' branches if used as an expression

此错误在此行显示

if (funs[0]==1)

如果我对此行发表评论,错误就会消失

funs.add(2) 

这很麻烦,因为很明显这是有效的if流控制语句。我没有使用if作为表达式。

显然,在此else上放置一个死掉的else {}if)也可以解决该错误,但不作解释。

科特琳游乐场:

Kotlin Playground

更新:正如Pawel向我指出的那样,这是一个类型返回冲突的问题,链接到with语句。由于我是经典的 Pascal 程序员,因此我使用with来了解Pascal用户是如何做到的。

为此,最好如Pawel所述,使用object.apply {}。因此,可以像with一样直接使用对象的属性和方法,而无需在方括号({})内插入访问点。

1 个答案:

答案 0 :(得分:1)

您正在使用具有with(AP[0]) { ... }的lambda签名的T.() -> R函数。它需要lambda内部的返回值,并且其中的最后一条语句是when块,因此它用作表达式来确定返回值。

引起错误是因为在cl == %funs[0]!=1的情况下,无法确定要返回的值。

使用不需要返回值的作用域函数(例如,带有签名with的{​​{1}})替换您的AP[0].apply { ... },以解决此问题。

编辑:为什么注释掉T.() -> Unit“修复”错误?

这是因为该调用返回了funs.add(2)值,该值更改了整个Boolean块的签名:

when

现在,当您注释掉// this when block can be used as an expression because it returns value of type Any when { (cl == "%") -> if (funs[0]==1) cl = "a" // if true returns Unit, else undefined cl == "xU" -> { funs.add(2) } // returns Boolean else -> cl="b" // does not return value (Unit) } 或将第二种情况更改为funs.add(2)时,这会使整个{funs.add(2) ; Unit }块的返回类型成为when,这意味着它不再用作表达式和返回值不是必需的。

Unit