scala言語学習のOption

3366 ワード

先日、Optionに関する文章を見ましたが、Null Pointerの発明者C.A.R.Hoare先生の話を引用しました。空引用は「10億ドルの誤り」です。
 
ここでは、戻り値が空の時に空の指針が異常になると主に言っていましたが、戻り値はOptionで包んだら、いずれは一つの対象に戻ります。もう空の引用には戻らないし、Null PointerExceptionもありません。この認識は間違っていませんが、今晩までプレイフレームの初期化コードを見て、Optionがどのような役割を果たしているのかが分かりました。いったいどうやって「10億ドル」を節約できますか?
 
プレイフレーム初期化時に設定に基づいてNettyServerを作成します。プロセスは以下の通りです。
 
  def main(args: Array[String]) {
    args.headOption.orElse(
      Option(System.getProperty("user.dir"))).map(new File(_)).filter(p => p.exists && p.isDirectory).map { applicationPath =>
        createServer(applicationPath).getOrElse(System.exit(-1))
      }.getOrElse {
        println("Not a valid Play application")
      }
  }
 最初はちょっと目まいがしました。こんなに長くて、またmapです。filterです。またorElseがあります。getOrElseです。意味が分かりません。振り返るしかないです。まずOptionのコードを調べてみます。
 
 @inline final def getOrElse[B >: A](default: => B): B =
    if (isEmpty) default else this.get
 getOrElseは、Optionが空であればパラメータの値を返します。そうでなければOptionの値を返します。ちなみに、ここのパラメータ値のタイプの前に「=」があります。これは後の値を求めるものです。いわゆるcall-by-nameパラメータです。Optionが空でないとパラメータは値を求められません。ここを見て、私達の製品コードの中の一山を思い出しました。以下のjavaコードです。
 
if (log.isDebugEnabled())
{
    log.debug("plaplapla");
}
 scalaを使って、log.debugのパラメータをcall-by-nameのパラメータと定義すれば、1行だけで解決できます。C++の中のやり方はマクロを定義することであり、醜悪な解決策でもある。
 
mapを再参照:
 
  @inline final def map[B](f: A => B): Option[B] =
    if (isEmpty) None else Some(f(this.get))
 Optionが空であれば、関数fによってマッピングされたOptionを返します。ここのNoneとSomeはOptionのサブクラスです。
 
filter類似:
 
  @inline final def filter(p: A => Boolean): Option[A] =
    if (isEmpty || p(this.get)) this else None
 空の場合、またはp関数がfalseに戻り、空のOptionに戻ります。そうでなければ、自分に戻ります。
 
最初の5行のコードを振り返ってみると、すぐにOptionの大きな強みを感じました。こんなに多くのパラメータの準備と検証をして、また空と判断しました。またファイルが存在するかどうかを判断します。カタログとしても、if文がありません。if elseのない副作用はエラー処理であり、とても優雅です。このコードはjavaで書いたら、大体こんな感じです。
 
public static void main(String[] args) {
    String dir = null;
    if (args.length == 1)
      dir = args[0];
    else
      dir = System.getProperty("user.dir");

    if (dir != null)
    {
      File f = new File(dir);
      if (f.exists() && f.isDirectory())
      {
         NettyServer server = createServer(f);
         if (server == null)
            System.exit(-1);
      }
      else
    	  System.out.println("not a valid play application");
    }
    else
       System.out.println("xxxx");
 }
 コードの長さはともかく、以前はこのようなJAVAコードの論理がはっきりしていると感じましたが、今はこれらのif elseがこのようにこじれています。
 
振り返ってみると、scalaの他のコードは、基本的にif文がないことが分かりました。この感じは先日erlangを使い始めたばかりの時、erlangコードにはほとんどif文がないことに気づきました。最初はとても違和感があって、プログラムが書けないことに気づきました。でも、とても速くて、case文ですっきりしました。
 
scalaを見て、javaを書きたくないです。