minimize

事業拡大のため、新しい仲間を募集しています。
→詳しくはこちら

関数の宣言

基本は以下のように形になる。

def oncePerSecond(callback: (v: Int) => String): Unit =
{
  ...
}

関数の定義ももはや変数と同じく、= によって代入されていることに注目しよう。

上の例で oncePerSecond は、callback という引数を取り、Unit 型を返す。
callback は、Int 型の引数を取り、String 型を返す関数。
この表記は慣れないうちは理解しにくいので覚えよう。

関数の省略記法

関数を定義するとき、引数の型は必ず指定しなければならない。
戻り値は、(文脈にもよるが)省略可能である。

def func(v: Int) = {
  ...
  "hello"
}

これは戻り値が無いわけではなく、Scala が型推測によってコンパイル時に戻り値の型を決定する。
上の例ならば、func の戻り値は String となる。

匿名関数

Java にあった無名クラスと同じようなもの。

List(5, 4, -1).foreach(func)

ここで func を匿名関数化すると以下のようになる。

List(5, 4, -1).foreach( (v: Int) => { println(v) } )

このように、

(引数) => { 本体 }

で匿名関数の完成だ。
匿名関数にするときは、戻り値の型は記述しない。
また、本体を囲う中括弧や引数の型も省略可能だ。

List(5, 4, -1).foreach( v => println(v) )

明らかに型が推測できれば、もしくは型を気にする必要がなければ、型は省略して良いだろう。
上のようなワンライナーの場合、省略した方がかえって読みやすい。

引数を取る関数の省略記法

少し難しくなるが、引数を取る関数も省略表記が可能だ。

list.foreach(println)

これは、以下のように解釈される。

list.foreach(v => println(v))

では、次はどうだろう。

xs filter (pivot >)

省略表記を無くしてみればわかりやすい。

xs filter (v => { pivot > v })

つまりこの文は、pivot より小さい値の集合を返す。

apply

Scala では、apply という関数は特別な意味を持つ。
オブジェクトに直接 () を付けて呼び出すと、そのオブジェクトの apply 関数が呼び出される。

args(0)

args の型は Array とする。
このとき、内部ではどのような処理が行われているかというと。
Array クラスの apply 関数が呼び出されている。つまり、以下の省略記法となる。

args.apply(0)

var による宣言

関数を再代入可能にするには、変数として定義する。

var doSomething: (Person) => Unit =
  (p) => println(p)

ちなみにこれを def で定義すると以下のようになる。

def doSomething(p: Person) {
  println(p)
}

このようにかなり記述法が異なるので注意しよう。

また、var 定義した関数を呼び出すときは明示的に () を付けなければいけない。
少し整理しよう。

通常形式

def time() : Long = { return System.currentTimeMillis }
time      // OK
time()    // OK

まずは通常形式。
このように引数無の関数を定義すると () を付けても付けなくても同様の結果を返す。

プロパティ形式

def time : Long = { return System.currentTimeMillis }
time      // OK
time()    // NG

プロパティ形式で記述した関数は () 付きで呼び出そうとするとエラーになる。

var 定義

var time : () => Long = () => System.currentTimeMillis
time      // 関数そのもの(function0)を返す
time()    // OK

var 定義すると、関数そのものとして扱われるようになり、() を付ければその結果が返される。