代码之家  ›  专栏  ›  技术社区  ›  DodgyCodeException

为什么编译器认为if语句是表达式?

  •  6
  • DodgyCodeException  · 技术社区  · 6 年前

    我使用这种方法比较排序后的列表,并告诉您列表2中缺少列表1中的哪些项,反之亦然,时间为o(n):

    fun <T : Comparable<T>> compareSortedLists(
            list1: Iterable<T>,
            list2: Iterable<T>,
            onlyInList1: MutableCollection<T>,
            onlyInList2: MutableCollection<T>) {
        val it1 = PeekingIterator(list1.iterator())
        val it2 = PeekingIterator(list2.iterator())
        while (it1.hasNext() && it2.hasNext()) {
            val comp = it1.peek().compareTo(it2.peek())
            if (comp < 0)       // <-- ERROR: type inference failure
                onlyInList1.add(it1.next())
            else if (comp > 0)
                onlyInList2.add(it2.next())
            else {
                it1.next()
                it2.next()      // <---- Error: type mismatch
            }
        }
        it1.forEachRemaining { onlyInList1.add(it) }
        it2.forEachRemaining { onlyInList2.add(it) }
    }
    

    Intellij IDEA 2018.1.4中的Kotlin编译器(1.2.41)给出了一个编译时错误(如上所示)。错误信息显示:

    Type mismatch.
    Required: Comparable<Boolean>!
    Found: T!
    

    但我没有打算 if 作为一种表达。我指的是一个语句(编辑:我指的是一个值被忽略的表达式,因为 如果 s实际上是表达式)。如果我转换 如果 when 然后它编译好:

            when {                // <-- Look, no error! ;-)
                comp < 0 ->
                    onlyInList1.add(it1.next())
                comp > 0 ->
                    onlyInList2.add(it2.next())
                else -> {
                    it1.next()
                    it2.next()
                }
            }
    

    为什么它认为 如果 是一种表达吗?而且,在所有的事情中,为什么它认为 Comparable<Boolean>! 是必需的吗?需要这种类型的上下文在哪里?

    1 回复  |  直到 6 年前
        1
  •  2
  •   Marko Topolnik    6 年前

    这似乎是一个编译器错误。我在这里报告的:

    https://youtrack.jetbrains.net/issue/KT-24886

    这是一个最小的复制器:

    fun <T : Comparable<T>> test(a: Iterable<T>) {
        val x = if (booleanExpr1())
            booleanExpr2()
        else if (booleanExpr3())
            booleanExpr4()
        else {
            a.iterator().next()
        }
    }
    
    fun booleanExpr1() = true
    fun booleanExpr2() = true
    fun booleanExpr3() = true
    fun booleanExpr4() = true
    

    注意,问题根本不在于“if表达式不被视为语句”,而在于类型推断本身。编译器应该计算出所有分支的有效上限,但失败了。