[Scala] 客製化Interpolation

scala的String Interpolation可以參考官方手冊
http://docs.scala-lang.org/overviews/core/string-interpolation.html

簡單來說就是字串可以加的前輟字,範例如下

s"hello $word"
raw"\\\\\\"

承襲上篇的[Scala for的妙用]

今天我想改造query method

query(conn, "select * from $table", prefix)

變成類似

SQL"select * from $table"

這樣的寫法

可以用官方手冊的客製化Interpolation進行改造

MyQuery.scala
  def query(conn:Connection, sql:String, prefix:String):List[String] = {
    var results:List[String] = List[String]()
    val stat = conn.createStatement()
    val rs = stat.executeQuery(sql)
    while(rs.next()){
      results = results  :+ (if(prefix.length > 0) s"$prefix." else "") + rs.getString(1)
    }
    rs.close();stat.close()
    results
  }

把query method獨立抽出來變成一個implicit class

SQLFactory.scala
package org.mygod

object SQLFactory{
  implicit class SQLHelper(val sc: StringContext) extends AnyVal {
    def SQL(args:Any*)(implicit conn:Connection):List[String] = {
      val prefix:String = if (args.size > 0) args(0).asInstanceOf[String] else ""
      val sql:String = sc.parts(0) + prefix

      var results:List[String] = List[String]()
      val stat = conn.createStatement()
      val rs = stat.executeQuery(sql)
      while(rs.next()){
        results = results  :+ (if(prefix.length > 0) s"$prefix." else "") + rs.getString(1)
      }
      rs.close();stat.close()
      results
    }
  }
}

這邊要注意的是implicit class SQLHelper的上層包裝(SQLFactory)必須是object而不能是class
否則會跑例外出來

而implicit class SQLHelper這是負起將StringContext轉型的任務

今天因為query函式只有一個參數prefix並且prefix=table name

因此可以寫的簡化點只接用sc跟args組合成sql query

實際更好的組合方法請參考官方手冊
http://docs.scala-lang.org/overviews/core/string-interpolation.html

而為了簡化傳遞參數這裡將Connection也implicit化,不直接從前輟字傳遞

最後要使用的時候原本的呼叫方式

MyQuery.scala
  val conn= getConnection()
  val tables = for (c <- query(conn, "Show catalogs", "");
                    s <- query(conn, s"Show schemas from $c", c);
                    t <- query(conn, s"Show tables from $s", s)
  ) yield t

修改成如下

MyQuery.scala
  implicit val conn= getConnection()
  import org.mygod.SQLFactory._
  val tables = for (c <- SQL"Show catalogs";
                    s <- SQL"Show schemas from $c";
                    t <- SQL"Show tables from $s"
  ) yield t

conn改用間接傳遞,雖然多import一個東西

但是在函式呼叫上清爽不少

comments powered by Disqus