使代码更符合函数风格



下面是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

最新更新