minimize

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

ちょっとしたネタや小技など。

Predef

Scala では標準で import されるクラスがある。それが、scala.Predef。
ここにはいくつも便利な定義があるから、必要に応じて使うと便利。

エイリアス

よく使う class や trait が定義してある。Map, Set, Pair など。

アサーション系

アサーション系の関数がいくつも定義されている。

require(d != 0)

このように記述しておけば、d != 0 が成立しないときに IllegalArgumentException がスローされる。

コンソール系

コンソール入出力系の関数。
print, println, readLine などが定義されている。

型変換

多くの型変換関数が Implicit で定義されている。
ちなみに、Scala では int → long の変換や Auto Boxing なども型変換関数を経由して行う。

関数の再定義(ユーザ定義関数)

関数をオブジェクトで扱えるようになると、こんなことが出来るようになる。

val bindi = new Person("Tabinda", "Khan", 38)
bindi.doSomething =
  (p:Person) => System.out.println("I edit textbooks")

doSomething は Person クラスに定義された関数だ。
クラス変数に値を代入できるように、クラスの関数にも別の関数を代入、つまり再定義ができる。
これは非常に強力な拡張方法だ。

通常の関数定義 def は val と同様に再代入が禁止されている。
よって、再定義可能な関数は var で定義する必要がある。

class Person {
  var doSomething: (Person) => Unit =
    (p) => println(p)
}

高階関数

関数はオブジェクトだから、関数の引数として関数を渡すことが可能となった。
このように、関数を引数に渡したり戻り値として返したりする関数を、高階関数(higher-order functions)と呼ぶ。

Java では関数の引数や戻り値にはデータしか使えなかったので、共通化の幅に限界があった。
ここに関数を使えることによって、プログラミングの方法を大きく変えることが可能になる。
これによってより徹底したDRY(Don't Repeat Yourself)も実現可能だ。

遅延参照

通常、クラス内で定義されたフィールドはインスタンス生成時に値が初期化される。

val manager: Employee = Db.get(managerId)

つまり上の文では、manager を初期化するために右辺が評価され、その結果 Db.get 関数を呼び出す。

lazy val manager: Employee = Db.get(managerId)

このように lazy キーワードを付けると、
manager を初めて参照するときに右辺が評価される。
もちろん、2回目以降に参照するときには右辺は評価されず manager の値がそのまま返される。

代入・参照関数

Scala では、var 定義した変数には自動的にそれらの Getter / Setter が作られる。

class Celsius {
  private var d: Int = 0
}

例えば上の定義では、内部的に以下の Getter / Setter を作成する。

def d: Int // Getter
def d_=(x: Int): Unit // Setter

このように、Getter は変数と同じ名前、Setter は {変数名}_= という関数名となる。
これらの関数は直接呼び出すことはできず、変数に代入・参照する際に自動的に呼び出される。

println(d) // d 関数が呼び出される
d = 5 // d_=(5) 関数が呼び出される

この命名規約を守って自分で関数を定義することもできる。

class Celsius {
  private var d: Int = 0
  def degree: Int = d
  def degree_=(x: Int): Unit = if (x >= 273) d = x
}

これは、以下のようになる。

println(degree) // d の内容が返される
degree = 500 // degree_=(500) が呼び出される

これによって記述的には変数のアクセスをフックしたような形になる。
つまりプロパティ機能の実現だ。

同名の class と object

Scala では、同名の class と object を同時に定義できる(共存可能)。

これは例えば、Bean に対する Factory クラスなどを作るときに有効な手法。
従来の Java の手法では、Bean に対する BeanFactory クラスを作っていたが
Scala では Bean と同名の object を作り、そこに Factory 関数を配置する。この方が自然だ。

あるサンプルの例では、認証無しの機能(誰でも呼び出し可能)を object で提供し
認証ありの機能(呼び出しにユーザ名とパスワードが必要なもの)を class で提供していた。
他にも色々な使い方ができるだろう。