Option型の利用
Option型は非常に便利な型ですのでここで紹介します。
Optionは、値が存在する場合としない場合の2通りの状態を表すコンテナです。
Optionはcaseクラスです。Option型には、サブタイプとして値が存在する場合のSomeと、値がない場合のNoneがあります。
どのように利用すべきか、例をもとに説明します。
Javaでは、java.util.Mapクラスのget( Object key )メソッドは、要素がない場合はnullを返しました。
scala> val jmap = new java.util.HashMap[String,String]
jmap: java.util.HashMap[String,String] = {}
scala> jmap.put( "A", "a" )
res1: String = null
scala> jmap.put( "B", null )
res2: String = null
scala> jmap.get( "A" )
res3: String = a
scala> jmap.get( "B" )
res4: String = null
scala> jmap.get( "C" )
res5: String = null
nullが返された場合、Mapの中に、keyに対応する値がnullに設定されているのか、それともkeyに対応する要素が存在しないのでnullなのか判断がつきません。上記の例では、keyを「B」でgetを呼び出した場合は前者で「C」で呼び出した場合は後者です。
Scalaで用意されているMapクラスのget関数はOption型を返します。keyに対して値が存在する場合はSome(値)でない場合はNoneです。
scala> val map = Map( "A" -> "a" , "B" -> null ) map: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map((A,a), (B,null)) scala> map.get( "A" ) res1: Option[java.lang.String] = Some(a) scala> map.get( "B" ) res2: Option[java.lang.String] = Some(null) scala> map.get( "C" ) res3: Option[java.lang.String] = None
このように、keyが存在する場合はSomeが返り、ない場合はNoneが返るので、JavaのMap型のような問題はありません。
また、Option型はcaseクラスです。前回、caseクラスについて簡単に説明しましたが、caseクラスとパターンマッチを利用して条件判断をさせることができます。
scala> map.get("A") match {
| case Some(v) => println("値は%sです。" format v )
| case None => println("値はありません。" )
| }
値はaです。
scala> map.get("C") match {
| case None => Some(v) => println("値は%sです。" format v )
| case None => println("値はありません。")
| }
値はありません。
また、Option型には、filter関数やmap関数が用意されいています。さらに、Option型がSomeだったら値を取り出し、Noneだったらデフォルト値を返すgetOrElseという関数が用意されています。
これらを組み合わせて、mapから文字列を取り出して文字数を数える処理は、このように書くことができます。
scala> val m = Map( "a" -> "foo" , "b" -> "baaaaaar" )
m: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map((a,foo), (b,baaaaaar))
scala> m.get( "a" ).map{ _.length }.getOrElse( -1 )
res1: Int = 3
scala> m.get( "c" ).map{ _.length }.getOrElse( -1 )
res2: Int = -1
このように、Mapの中にkeyに対応する値がある場合は文字数を、ない場合は-1を返す処理を、if文を用いずに書くことができました。
JavaのMapを利用してこのような処理をする場合は、getメソッドで返される値がnullであるか、if文でnullチェックをする必要があるでしょう。nullチェックは、ともすれば書くのを忘れてしまい、思わぬNullPointerExceptionが発生する原因となります。
ScalaでOption型を利用することによって、このようにnullチェック忘れでNullPointerExceptionが発生するようなケアレスミスを駆逐することができます。
まとめ
今回は、Scalaが持つ関数型言語しての側面を解説しました。
関数をオブジェクトとして取り扱うことで、手続き型のプログラミングモデルとは異なった柔軟なプログラミングが可能になります。
次回Scalaでのクラスやトレイトの使い方、パターンマッチの詳細について、踏み込んだ解説をする予定です。
参考資料
- The Scala Programing Language
- 『Programming in Scala』 Martin Odersky・Lex Spoon・Bill Venners 著、Artima Inc、2008年11月
- 『Scalaスケーラブルプログラミング』 Martin Odersky・Lex Spoon・Bill Venners 著、羽生田栄一 監修、長尾 高弘 訳、インプレスジャパン、2009年8月
- 『Scalaプログラミング入門』 David Pollak 著、大塚庸史 訳、羽生田栄一解説、日経BP社、2010年3月
- Welcome to Scala hack-a-thon #1’s documentation!
