1. 程式人生 > >[Scala] 客製化Interpolation « Terrence的宅宅幻想

[Scala] 客製化Interpolation « Terrence的宅宅幻想

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

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

今天我想改造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

而為了簡化傳遞引數這裡將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一個東西

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