我具有以下功能:
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 ret
行ret
中用红色下划线,并且在尝试编译时给我错误:
变量“ ret”必须初始化
从我的角度来看,ret
似乎总是被初始化。我想念什么?
是因为初始化发生在lambda中,并且编译器不能保证变量已初始化?
答案 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语句。