首页 > 解决方案 > 为什么 Kotlin 编译器在有效的 IF 语句中给出错误?

问题描述

它开始在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用作表达。

显然在这上面加上一个死elseelse {}if也可以解决错误,但不要解释它。

科特林游乐场:

科特林游乐场

更新:正如 Pawel向我指出的那样,这是一个类型返回冲突的问题,与with语句相关联。因为我是一个经典的Pascal 程序员,所以我在使用withPascal 用户是如何做到的。

为此,最好像 Pawel 所说,使用object.apply {}. 因此,在 的情况下with,可以直接使用对象的属性和方法,而无需括号 ({}) 内的访问器点。

标签: androidkotlin

解决方案


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

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

with通过用不需要返回值的范围函数替换你来修复它,例如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 }this 时,整个when块的返回类型为 a Unit,这意味着它不再用作表达式并且不需要返回值。

// this when block cannot be used as an expression because it always returns Unit (void)
when {
    (cl == "%") -> if (funs[0]==1)  cl = "a"  // does not return value (Unit)
    cl == "xU" ->  { funs.add(2); Unit }    // ignore add return value by returning Unit
    else ->  cl="b"        // does not return value (Unit)
}

推荐阅读