はじめに
Scala の文法なのか、ScalikeJDBC固有の文法なのかを切り分けるために、まずはScala固有の文法で知っておきたいコードを紹介します。
1.string interpolation (文字列補間)
Scalaでは、変数宣言した変数名を文字列内で指定して、実行時に値を入れ替える事ができます。
例)
var name = "Sam"
println(s"Hello, ${name}")
> Hello, Sam
\${name}の箇所に"値"が出力されます。
2行目のs""の文字列内${name}は、最初の行で宣言したnameの値で置き換えられます。
変数と文字列リテラルを"+"でつなぐ必要なく、変数を文字列内で利用できます。
詳しくは以下をご参照ください。
Scala Doc: string interpolation (文字列補間)
2.implicit (暗黙)
Scalaにはコードを書かなくても、別のところで宣言したコードを意識せずに呼び出す事が可能です。
First Exampleで利用しているのは、 implicit parameter(暗黙のパラメータ)です。
引数を明記しなくても、まるで記述してあるかのように関数を呼び出す事ができます。
例)
implicit val implicitMsg:String = "暗黙の教え"
def printImplicit(implicit x: String) = println(x)
printImplicit
>暗黙の教え
本来は printImplicit を呼び出すときに引数が必要ですが、ここでは省略しています。
・引数定義の際(implicit x: String)にimplicitを指定
・implicit宣言した変数(implicit val implicitMsg:String)が同一スコープ内に存在する
と、引数が適用された関数を実行する事ができます。
この文法を利用する事で、SQL実行時にDBのセッション情報を毎回渡さなくても実行する事ができます。
execute.apply()は、実は、
execute.apply()(implicit session: DBSession)と定義されています。
(applyに『()』が2つあるのは『カリー化』と呼ばれるもの)
"implicit val" 宣言をスコープ内で宣言しておく事で、実行時にパラメータを明記しなくてもよくなっています。
First exampleの他のapplyも同様の形式です。
3.関数リテラル
foreachやmapの括弧内で使われている『(引数)=>(本体)』が関数リテラルです。
関数リテラルは代入したり、引数に渡したりする事ができます。
例)
List("Alice", "Bob", "Chris") foreach { name =>
println(name)
}
リテラルの意味がとらえにくいかもしれませんが、"関数"を"値として直接宣言"したものが関数リテラルです。
上記例では、 foreach と言う関数に、 "『nameと言う引数』を『標準出力に出力する』関数"が宣言されています。
4 map / foreach
Scalaの学習を進めると、コレクションが多数出現します(ListとかSeqとか)。
そのコレクションを操作する際の関数が同一名称(map,foreach, ・・・)で提供されています。
例えば、
・map関数は引数の関数リテラルを実行して、結果のコレクションを返す。
・foreach関数は引数の関数を実行するが、結果を返さない。
と言った関数が存在し、それぞれの機能はどのコレクション(List、Map、Seq etc)でも存在します。
以下コードの例です。
例)
val tempList_map = List("Alice", "Bob", "Chris") map { name =>
" Hello " + name + "!"
}
println(tempList_map)
>List( Hello Alice!, Hello Bob!, Hello Chris!)
map関数では名前の前に Hello が付与された文字列のコレクションが返されます。
例)
val tempList_foreach = List("Alice", "Bob", "Chris") foreach { name =>
" Hello " + name + "!"
}
println(tempList_foreach)
>()
foreach では、何も返されません。 Unit型が返されます(Javaで言うvoidみたいなもの)。
5.type parameter
Javaで言う所のジェネリクスです。コレクション等に含まれる値の型が保証されます。
下記の例では、Listに含まれる値の型をStringやIntegerで指定した例です。
◯ ・・・ val names : List[String] = List("test","test2")
◯ ・・・ val numbers : List[Integer] = List(123,654)
× ・・・ val numbers2 : List[Integer] = List(123,654,"456")
最後の例は、Integer型のListに文字列を含んでいるためコンパイルエラーになります。
6.collection
ふたつ前でコレクションで良く利用する関数の紹介をしましたが、ここではコレクションそのものの紹介です。
沢山のコレクションが提供されていますが、代表的なものを3つ紹介します。
・Seq ・・・ 要素の順番を保持したコレクションです(trait)。
・List ・・・ Seqの孫クラスで順序が保証されたコレクションです。
・Map ・・・ キーと値のコレクション
Scalaでは、頻繁にList(リスト)クラスを見かけます。JavaのArrayList的なイメージ考えると "Add"で要素が追加できそうですが、追加できません。
追加する時には『::』を使います。
例)
val names : List[String] = List("test","test2")
val names2 = "test3" :: names
println(names2)
>List(test3, test, test2)
7.apply / unapply
Scalaの文法としては、apply/unapplyは特殊な関数として定義されています。
・apply ・・・ オブジェクトでapply を省略して、『()』とコーディング可能な関数。
・unapply ・・・ 値を分割して、オブジェクトを生成する関数。
例)
object Japanese {
def apply(firstName: String, lastName: String) = s"${firstName} ${lastName}"
def unapply(jpName: String): Option[(String, String)] = {
var splitChar = jpName split " "
if(splitChar.length == 2) Some(splitChar(0), splitChar(1)) else None
}
}
val jpManApply = Japanese("鈴木", "一郎")
val jpManUnapply = Japanese.unapply("佐藤 次郎")
println(jpManApply)
println(jpManUnapply)
> 鈴木 一郎
> Some((佐藤,次郎))
applyは省略して記述できており、unapplyは自動的に姓名が半角スペースで分割されています。
なお、ScalikeJDBCでは、頻繁にapplyが呼ばれます。ScalikeJDBCでは、SQL文を『実行』する際に呼ばれます。
sql"XXXX".execute.apply()
や
sql"XXXX".update.apply()
と言った具合です。
8.case class(ケースクラス)
ケースクラスはJavaのBeanとかDtoとか呼ばれるクラス定義の、Getter/Setterを記述しなくてもフィールドが簡単に定義可能なクラスです。更に、オブジェクト同士の比較にも便利な仕組みが用意されています。
これがcase class(ケースクラス)です。
例
case class Student(firstName : String, lastName: String, schoolYear: Int)
// new 無しで、下記のようにインスタンスを生成できます。
val taro = Student("太郎","大阪",6)
”case class”を宣言することで、"apply / unapply"で紹介したコンパニオンオブジェクトのapplyメソッドが実装されます。
9.Option型
値が"有るか"、"無いか"を表現できる型です。
・値が存在する場合: Some[x]
・値が存在しない場合: None
Some[x]は"type parameter"で紹介した内容です(xは任意の型)。
例えばデータベースからデータを取得するメソッドにて、結果が"取得出来たか"、"取得出来なかった"のかを表現できます。
Scalaでは、何かしらの値を取得する際に、結果が無い場合にデフォルト値を設定可能なメソッド "getOrElse(デフォルト値)"が推奨されているようです(単純なgetよりも)。
例
val studentNo1:Option[Student] = Some(Student("太郎","大阪",6))
val studentNo2:Option[Student] = None
val classA = List(studentNo1,studentNo2)
for(s <- classA) println(s.getOrElse(Student("-","-",999)))
>Student(太郎,大阪,6)
>Student(-,-,999)
この例では、classAの2番目の要素は存在しません(None)。
そのため、標準出力する際に、getOrElseを利用して、Noneの場合にはデフォルト値を出力しています。
存在しない場合の処理を記述して、NullPointerExceptionを無くすことができます。
以上が、Scalaの文法の簡単な紹介となります。
ここで出てきた内容と次回紹介する内容を読めば、切り分けができるようになり、ScalikeJDBCの理解が深くなればいいな。