Ric*_*odd 8 scala list-comprehension jdbc
只需使用基本的JDBC接口即可使用Scala读取一些数据.在F#中(使用System.Data.SqlClient命名空间),我们可以执行类似这样的操作,从数据库返回不可变列表.
let rs = cmd.ExecuteReader()
[while rs.Read() do yield rs.GetInt32(1)]
Run Code Online (Sandbox Code Playgroud)
在Scala中,这被证明更加困难,据我所知,没有像F#这样的"同时"理解.实际上,我想在Scala中做一些接近F#的事情,而不必使用可变变量 - 如果只是因为它们看起来很难看并添加到代码行中.
这样的东西现在似乎在我的Scala代码中很常见:
var result = Seq.empty[Int]
val rs = stmt.executeQuery()
while (rs.next()) {
result = result :+ rs.getInt(1) }
Run Code Online (Sandbox Code Playgroud)
我会创建一个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
Run Code Online (Sandbox Code Playgroud)
您可以在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)
Run Code Online (Sandbox Code Playgroud)
惯用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)
Run Code Online (Sandbox Code Playgroud)
但如果您真的错过了这种语法,可以添加它:
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)
Run Code Online (Sandbox Code Playgroud)
您可以将隐式类与隐式类一起使用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()
}
}
}
Run Code Online (Sandbox Code Playgroud)
像这样使用:
import MyResultSetContainer._
val rs = stmnt.executeQuery("select * from pg_user")
val names = for (row <- rs) yield (row.getString(1))
println(names)
rs.close()
Run Code Online (Sandbox Code Playgroud)
for comprehension使用map引擎盖,所以如果你喜欢map直接:
val names = rs.map(row => row.getString(1))
Run Code Online (Sandbox Code Playgroud)
产生一个序列.由于CanBuildFrom您可以通过明确提供类型来生成其他集合:
val names: List[String] = rs.map(row => row.getString(1))
Run Code Online (Sandbox Code Playgroud)
CanBuildFrom工作怎么样?Scala编译器会查看此表达式中涉及的类型:结果类型和map调用的函数返回的类型.根据此信息,Scala编译器隐式提供工厂,可用于创建合适的构建器.因此,您只需要一种方法来生成不同类型的集合.
如果要返回多个值,只需返回一个元组:
val columns = rs.map(row => (row.getInt(2), row.getString(1)))
Run Code Online (Sandbox Code Playgroud)
并且元组可以用于Map直接创建:
val keyNamesMap: Map[Int, String] =
rs.map(row => (row.getInt(2), row.getString(1)))
Run Code Online (Sandbox Code Playgroud)
这是基于结果集是行列表的想法,因此该map函数应该在它之上可用.隐式类用于隐式地将map方法添加到基础结果集.
| 归档时间: |
|
| 查看次数: |
540 次 |
| 最近记录: |