为什么Kotlin坚持要对`ret`变量进行初始化?

时间:2019-11-27 14:07:25

标签: kotlin

我具有以下功能:

override fun countForTicket(dbc: SQLiteDatabase, ticketId: Long): Int {
    var ret: Int

    dbc.query(
        TABLE_SECOND_CHANCE_PRIZES, arrayOf("count(id)"),
        "ticket = ?", arrayOf(ticketId.toString()),
        null, null, null
    ).use { c ->
        ret = if (c.moveToFirst()) {
            c.getInt(0)
        } else {
            0
        }
    }


    return ret
}

问题在于,return retret中用红色下划线,并且在尝试编译时给我错误:

  

变量“ ret”必须初始化

从我的角度来看,ret似乎总是被初始化。我想念什么? 是因为初始化发生在lambda中,并且编译器不能保证变量已初始化?

2 个答案:

答案 0 :(得分:5)

编译器不够聪明,无法确定lambda将运行一次,因此无法为您解决这个问题。

我们对许多标准库高阶函数没有此问题的原因是它们利用协定,这些协定告诉编译器它们对传入的lambda所做的工作(例如保证lambda将只被调用一次)。

不幸的是,Closeable.use()没有指定合同(可能是因为它重新抛出了异常?)。

但是use确实会返回调用lambda的结果,因此您可以这样做

val ret = dbc.query(...).use { c ->
    if (c.moveToFirst()) {
        c.getInt(0)
    } else {
        0
    }
}

答案 1 :(得分:3)

编译器不允许返回不安全的变量。变量必须始终是某些东西。

在您的情况下,with_state在lambda内部初始化。编译器不知道此lambda是否已执行。如果不是,则ret保持其不安全状态。最后抛出ret

如果您确定始终分配此变量,则可以查看lateinit variables。您还可以为其设置默认值NullPointerException并省略else语句。