LoginSignup
3
3

More than 5 years have passed since last update.

ScalikeJDBCのFirst exampleを読むための知識(2)

Last updated at Posted at 2016-05-31

はじめに

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の理解が深くなればいいな。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3