Вот код 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" переводит на "карту" и "фильтр" в моем случае, интересно, почему это не работает:
if.(cursor.moveToFirst()) cursor.filter(_.moveToNext()).map { x => parse(x) }
Этот код основан на java.sql.ResultSet
, но шаблон должен быть применим и к вашему делу.
Вы можете определить класс следующим образом:
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
}
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)
}
Вы также можете использовать Iterator
для "понимания". И это дает вам доступ к API полной коллекции, например, к map
и т.д.
fold
проходящий вдоль курсора, если вы хотите избежать императивных циклов.filter
, вы можете использовать предикат, всегда разрешающий значениеtrue
чтобы получить все строки запроса.