使用基本的JDBC接口使用Scala读取一些数据。 在F#中(使用System.Data.SqlClient命名空间),我们可以这样做,从数据库中返回一个不可变列表。
let rs = cmd.ExecuteReader()
[while rs.Read() do yield rs.GetInt32(1)]
在Scala中,这被证明更加困难,据我所知,没有像F#这样的“同时”理解。实际上,我想在Scala中做一些接近F#的事情而不必使用可变变量 - 如果只是因为它们看起来很难看并添加到代码行中。
这样的东西现在似乎在我的Scala代码中很常见:
var result = Seq.empty[Int]
val rs = stmt.executeQuery()
while (rs.next()) {
result = result :+ rs.getInt(1) }
答案 0 :(得分:9)
我会创建一个包含查询结果的Iterator
自定义子类。这真的很容易; senia展示了如何。
但你也可以
val rs = stmt.executeQuery
val it = Iterator.continually(if (rs.next()) Some(rs.getInt(1)) else None)
val result = it.takeWhile(_.isDefined).toList.flatten
答案 1 :(得分:7)
你可以在scala中使用相同的方式,但我认为这很难看:
class Reader(var i: Int){
def read = { i-=1; i > 0 }
def getInt32 = i
}
val r = new Reader(10)
Stream.from(0).takeWhile{ _ => r.read}.map{ _ => r.getInt32}.toList
// List(9, 8, 7, 6, 5, 4, 3, 2, 1)
惯用scala方式是将您的Reader
转换为Iterator
:
implicit class ReaderIterator(r: Reader) extends Iterator[Int] {
def hasNext = r.read
def next = r.getInt32
}
scala> new Reader(10).toList
res0: List[Int] = List(9, 8, 7, 6, 5, 4, 3, 2, 1)
但如果您真的错过了这种语法,可以添加它:
import scala.collection.immutable.VectorBuilder
class FWhile(c: => Boolean){
def apply[T](e: => T): Seq[T] = {
val b = new VectorBuilder[T]
while (c) b += e
b.result
}
}
object FWhile{
def apply(c: => Boolean) = new FWhile(c)
}
scala> FWhile(r.read){r.getInt32}
res0: Seq[Int] = Vector(9, 8, 7, 6, 5, 4, 3, 2, 1)
答案 2 :(得分:5)
您可以将隐式类与隐式CanBuildFrom
一起使用。这确实使用了一个可变构建器,但不是在调用者端:
object MyResultSetContainer {
implicit class MyResultSet(rs: ResultSet) {
def map[T, C <: Iterable[T]](f: (ResultSet) => T)
(implicit cbf: CanBuildFrom[Nothing, T, C]): C = {
val builder = cbf()
while (rs.next()) {
builder += f(rs)
}
builder.result()
}
}
}
这样使用:
import MyResultSetContainer._
val rs = stmnt.executeQuery("select * from pg_user")
val names = for (row <- rs) yield (row.getString(1))
println(names)
rs.close()
for comprehension使用了map
,所以如果您直接选择map
:
val names = rs.map(row => row.getString(1))
产生序列。感谢CanBuildFrom
您还可以通过明确提供类型来生成其他集合:
val names: List[String] = rs.map(row => row.getString(1))
CanBuildFrom
如何运作? Scala编译器会查看此表达式中涉及的类型:结果类型和map调用的函数返回的类型。根据此信息,Scala编译器隐式提供工厂,可用于创建合适的构建器。因此,您只需要一种方法来生成不同类型的集合。
如果要返回多个值,只需返回一个元组:
val columns = rs.map(row => (row.getInt(2), row.getString(1)))
并且元组可用于直接创建Map
:
val keyNamesMap: Map[Int, String] =
rs.map(row => (row.getInt(2), row.getString(1)))
这是基于结果集是行列表的想法,因此map
函数应该可用于它。隐式类用于隐式地将map
方法添加到基础结果集。