下面是Java-Scala代码:
class MyDbManager extends SQLiteOpenHelper ....
val cursor = new MyDbManager().getReadableDatabase.query(....)
val result = new ArrayList[MyItem] //???
//?????????
if (cursor.moveToFirst()) {
do {
result + parse(cursor)
} while (cursor.moveToNext())
}
//?????????
cursor.close()
result
我想做的是能够不使用任何可变集合和不可变集合与可变变量。我想这样做:
val result = if (cursor.moveToFirst()) {
do { parse(cursor) } while (cursor.moveToNext())
}
你明白了:不要使用任何冗余变量,尤其是可变变量。当然,上面的代码无法编译。
如果可能的话,我该怎么做呢?我希望不涉及任何第三方库,越简单越好。
:有人建议用"for"。既然"for"在我的例子中翻译成"map"one_answers"filter",我想知道,为什么这不起作用:
if.(cursor.moveToFirst()) cursor.filter(_.moveToNext()).map { x => parse(x) }
这段代码是基于java.sql.ResultSet
的,但是该模式也应该适用于您的情况。
选项1:提供foreach方法
可以这样定义一个类:
class Cursor[T](rs: ResultSet)(f: Row => T) {
def foreach(g: T => Unit) {
val row = new Row(rs)
while (rs.next()) {
g(f(row))
}
}
}
有两个参数:
- 底层结果集
- 为每行生成一个实例的函数
f
。因此在迭代期间,基于当前行的实例被构造。
Cursor
类提供了foreach
方法。所以它可以用在"为了理解"中:
val cursor = Cursor(rs) {
row =>
Person(row.getString(1), row.getString(2))
}
for {
person <- cursor
} {
println(person)
}
为了能够对函数f
使用{ ... }
语法,需要一个伴随对象:
object Cursor {
def apply[T](rs: ResultSet)(f: Row => T) = {
new Cursor(rs)(f)
}
}
使用包装器类Row
表示结果集的一行,因为底层结果集的一些方法不应该对函数可见(如next()
)。
class Row(rs: ResultSet) {
def getString(n: Int) = rs.getString(n)
def getInt(n: Int) = rs.getInt(n)
// ... more getters for other types
}
选项2:扩展迭代器
class CursorWithIterator[T](rs: ResultSet)(f: Row => T) extends Iterator[T] {
private val row = new Row(rs)
override def hasNext = rs.next()
override def next() = f(row)
}
您也可以在a中使用Iterator
来表示"理解"。它让你可以访问完整的集合API,如map
等