5.3 配列には Array クラスを使う この関数の引数の lnt 型は、型推論によって省略して次のように記述できます。 さらに 括弧 ( かっこ ) も省略できます。 numbers . foreach( (number) = > println(number) ) numbers . foreach(number = > println(number) ) 引数がコードプロック中に一度しか登場しない場合は、プレースホルダであるアンダー スコ また、 アを使って、以下のように簡潔に記述できます。一度しかプレースホルダが登場しない場合はプ val fruits = Array("app1e" "bananatt) ています。 Array の生成例は以下の通りです。 Java での配列は int[] や Object[] などで記述しますが、 Scala では Array というクラスになっ 5.3 配列には Array クラスを使う 記述できます。 foreach メソッドに渡す関数の処理が複数行ある場合は、メソッドの括弧を中括弧 { } に変えて numbers . foreach(println) / / ーを省略 numbers . foreach(println(—) ) レースホルダ自体を省略できます。 val fruit2 = fruits(2) / / 例外が発生 〃↑工概 s. 叩ァ切 ( 1) の糖衣構文 val fruitl fruits(l) / / と佖れ 0 れ佖 ソッドへの糖衣構文になっている丸括弧 ( ) を利用します。 要素を取得する場合、 Java では配列の添え字をカギ括弧 [ ] で囲みますが、 Scala では apply メ ななか十 inside press ◆ 24 fruits . foreach(println) 〃 foreach 版 println(fruit) for(fruit く一 fruits){ 〃工。版 示します。 / / ↑工れ s. 面 te に , " c ん e " ) の糖衣構文最後に、要素を繰り返し処理する場合を以下に ttcherry fruits(l) しますが、これは update メソッドへの糖衣構文になっています。 Java の配列と同様、 Array は要素を更新できます。要素の取得と同様、添え字は丸括弧で指定
6 ScaIa プログラミングに欠かせない機能 , こからは、 ScaIa プログラミングに欠かせない「パターンマッチ」と、独自機能である「ケー スクラス」、そして「トレイト」について説明します。 6.1 match 式による柔軟なパターンマッチ ななか十 inside press ◆ 25 case " 2 " = > "two" 〃文字列の値の場合 case n:lnt = > 'tone" / / 工れ t 型の場合 0bj match { def convertNumberToString(0bj : Any) リスト 29 match 式は値を返す numberMatch(4) / / 0t れ e numberMatch(3) / / t 出 0 0 three numberMatch(2) / / t 田 0 0 three numberMatch(I) / / 0 れ e C e = > println("other") case 2 ー 3 = > println("two or three") case 1 = > println(t'one't) def numberMatch(n : lnt) = Ⅱ match { リスト 28 数値のマッチングの例 を返すことができます。 = > の後で最後に評価された式の値を戻り値として返せます。 List 型の条件を指定して文字列を返しています。リスト 29 で見たように、 match 式では戻り値 字列やコレクション、型によるマッチングが可能です。リスト 29 の例では lnt 型や文字列の値、 はワイルドカードといって、 switch 文の default: に相当します。また、 Scala の match 式では、文 case 1 で変数 n が 1 に該当すれば = > の次の処理の println("one") が実行されます。また、 case ー た case を処理したら、他の case を処理せずに match 式の制御を抜けます。例えば、この例では、 述しなければ後続の選択肢の処理を実行しますが、 match 式では break はありません。マッチし 用し、 case による選択肢は上から下へと順番に検証されます。 Java の switch 文では break を記 数値でのマッチの例がリスト 28 です。変数 n ( セレクターと呼びます ) に対して、 match 式を適 6.2 数値や文字列などでマッチング可能 match 式を利用します。 ができ、 Scala プログラミングの中心的な役割を担います。パターンマッチの処理を記述するには ターンマッチは多くの言語で採用されていますが、 ScaIa のものは様々な条件にマッチさせること ScaIa のパターンマッチは、 Java の switch 文をより強化した場合分けの機能を提供します。パ
3.2 クラスが簡潔に書ける ます。 リスト 13 補助コンストラクタの例 package money import java. uti1. Currency import Java. util . Loca1e class Money (val amount : BigDecima1 , val currency : 〃↓補助コンストラクタ this (amount , def this (amount : BigDecimal) Currency ・ getlnstance (Loca1e. getDefau1t) ) Currency) { 〃以下、省略 リスト 14 val a = new Money(100) / / プ 00 円 println(). amount) val b = new Money(50) / / 50 円 println(). amount) val result = a. plus(b) / / プ 00 円 println(result . amount) リスト 13 用のテストコード + 50 円 new Money()5 の ) / / プ 50 円かどうか検証 assert (result 3.2.5 オプジェクトでインスタンスを一つに限定 Java では、よく使う値を staticfinal なクラスフィールドで定義します。 Scala で書いた Money クラスでも、 Currency を円にするなど定数のようにできないものでしようか。 通常のクラスだけでは以下のようにインスタンス化しないで定数フィールドを参照することは できません。 val usdCurrency = Money. USD scala では static final の代わりにオプジェクトが使えます。 He110,World の節で紹介した HelloWorId がオプジェクトでした。このオプジェクトは一見すると、 object キーワードで宣言 するクラスのようなものですが、複数のインスタンスが作成できるクラスとは違い、一つのイ ンスタンスしか生成できません。デザインパターンのシングルトン ( クラスのインスタンスが一 つしか生成されない ) を言語としてサポートしているわけです。使用する場合の注意点は、オプ 合に暗黙的に指定する引数のことです。 class Money(var amount: BigDecimal,var currency: Currency Currency. getInstance(Locale. getDefault) ) . ななか十 inside press ◆ 16
5.2 高階関数を使って繰り返し処理を作る しいインスタンスを返すことになっています、 12 ( リスト 24 ) 。 それでは、この List の各要素を表示する処理を記述してみましよう。二通りの書き方を示しま す。ーっは Java などと同様の命令型の考え方に基づく書き方 ( リスト 25 ) 、 val val val 文と同じように要素を順次取り出す書き方です ( リスト 26 ) 。 : numbers / / 先頭に 0 に追加。 s カ ( の 0 + : numbers / / 先頭に 0 に追加。 List(O, , 2 , 3 ) リスト 24 要素を追加する例 val newNumbers2 val newNumbers 1 val numbers = List ( 1 newNumbers4 = numbers : + 4 / / 末尾にイを追加。を st ( プ , 〃↑末尾に s カ 4 , 5 ) を追加。 List(), 2 , 3 , イ , 5 ) newNumbers3 = numbers + + List(), 5 ) 2 , もうーっが拡張 for 2 , 3 ) 2 , 3 ) 3 , イ ) リスト 25 List の各要素を表示する二通りの方法 ( Java の f 。 r 文に相当する書き方 ) numbers = List ( 1 , 2 , 3 , 4 , 5 ) / / Ja セ 0 の″工 0 ( れ t を = 0 , ・をくれ m と e s ユ e れ gt ん , ・を + + ) { ″に相当 for(i く一 0 until numbers . length) { println(numbers(i)) 〃添え字で要素を取得 リスト 26 List の各要素を表示する二通りの方法 ( Java の拡張 f 。 r 文に相当する書き方 ) val numbers = Li st ( 1 , 2 , 3 , 4 , 5 ) / / 五セ 0 の〃工 or ( e 乙 eme れカ : れし ers ) { ″に相当 f0 て (number く一 numbers) { println(number) 5.2 高階関数を使って繰り返し処理を作る List には foreach メソッドという高階関数があります。リスト 27 の例では、 foreach メソッド の引数には、無名関数を与えています。この無名関数の型は、その要素型である lnt を引数に取 り、戻り値は U ⅲ t です。これを要素ごとに呼び出して繰り返し処理を実現します。 リスト 27 List の foreach メソッドを使って要素を表示する List を得るには filiterNot メソッドを使うとよいでしよう。 * 12List 同士の連結には十十演算子以外に : : : 演算子も利用可能です。また、 List から不要な要素を取り除いた新たな numbers. foreach( (number : lnt) = > println(number) ) val numbers = List ( 1 , 2 , 3 , 4 , 5 ) ななか十 inside press ◆ 23
3.2 クラスが簡潔に書ける val currency = Currency ・ getlnstance ( "JPY" ) / / 円の通貨単位 val a = new Money(100, currency) / / プ 00 円 println(). amount) / / プ 00 val b = new Money ( 50 , currency) / / 50 円 println(). amount) / / 50 〃プ 00 円 + 50 円 val result = a. plus (b) println(result . amount) / / プ 50 new Money ( 150 , currency) val answer assert (result . amount answer . amount & & result . currency = = answer. currency) / / プ 50 円かどうか検証 3.2.2 メソッドを実装する Money クラスをさらに利用してみましよう。 100 円と 50 円を加算した場合の結果が 150 円に なっているかを検証するテストコードの例をリスト 10 に示します。 Money クラスの plus メソッ ドはまだ存在しないのでエラーになります。 Money クラスに plus メソッドを実装する前に、メ ソッドの基本知識を知っておきましよう。少し複雑な処理をある程度のまとまりでメソッド化す ることがよくあります。例えば、次の例は二つの数値を加算した結果を返す add という単純なメ return a 十 b def add(a:lnt, b:lnt) :lnt ソッドです。 ななか十 inside press ◆ 14 * 8 式とは一般に値や変数、演算子、関数の組み合わせのことを指します。式は評価された値を持ちます。 * 7 処理途中でメソッドの呼び出し元に戻る場合は return を記述する必要があります。 a + b ただし、引数の型は省略できませんので注意してください。 def add(): lnt, b: lnt) さらに変数の型推論と同様、メソッドの戻り値についても型推論により次のように省略できます。 def add(a:lnt, b:lnt):lnt = a + b 体のプロックを省略できます。そのため、次のような簡潔な記述が可能です。 return を省略できます * 7 。また、メソッド本体の処理が一つの式 * 8 で終わる場合は、メソッド本 算結果の値を return で返しています。ただし、関数の最後に評価した式の値が戻り値になるため、 HeIIo,WorId の節の main メソッドで説明した通りですが、 add は値を返すところが違います。加 add に 1 と 2 の値を渡して加算し、 3 という結果を得ています。メソッドのシグニチャの意味は、 val result = add(), 2 ) / / 3
6.4 トレイトは実装コードを書けるインタフェ ース println(greeting. getMessage) def main(args : Array [String] ) { args match { case Array(1ang, user) = > lang mat ch { case = > pri Ⅱ tl Ⅱ ( " 指定されたあいさつは実行できません。 " ) case "EN" = > say (new GreetingEng1ish(user) ) case "JP't = > say (new GreetingJapanese (user) ) リスト 32 複数のトレイトを使ったミックスインの例 = > println ( " 引数の数が不正です。 " ) } ななか十 inside press ◆ 28 / / 読み込み専用リポジトリの宣言 entities + = (employee . id ー > employee) def save (employee : Emp10yee) : Unit this: Emp10yeeRepositoryBase = > / / this 型の指定 trait Writab1eEmp10yeeRepository { / / 書き込み専用のリポジトリ機能 def load(key : lnt) : Emp10yee entities(key) this: Emp10yeeRepositoryBase = > / / this 型の指定 trait Readab1eEmp10yeeRepository { / / 読み込み専用のリポジトリ機能 def toList entities . toList def toMap = entities Map. empty [lnt , Emp10yee] private [repository] var entities abstract class Emp10yeeRepositoryBase { 〃従業員情報を保持するリポジトリの骨格実装 case class Emp10yee(id: lnt, name: String) / / 従業員 package repository
val resultl val resu1t2 val resu1t3 リスト 22 値としての関数を呼び出す square(2) / / es 乙 t プ = イ squareDebug(2) 〃 resuLt2 = イ標準出力にイを表示 square("aaa") / / 第一引数の型がコンパイルエラー val resu1t4:String = square(2) / / 戻り値の型がコンパイルエラー リスト 23 関数をメソッドの引数や戻り値に利用する / / 関数を引数に取る関数 def debugprint(): lnt, func: (lnt) = > lnt) { func (x) va1 result println(result) debugPrint(10, square) / / プ 00 が表示される / / デバッグ版の s 。メソッドを返す関数 def newSquareDebugFunc = { val squareDebugFunc = (x : lnt) = > { square (x) println(result) va1 result result squareDebugFunc val squareDebug = newSquareDebugFunc squareDebug(5) / / 25 が表示される va1 result 5 Scala と」 ava のコレクションの違い こで、関数と深い関係にあるコレクションについて説明します。 Java との違いが際立っ List と Array について見ていきましよう。 5.1 List の生成と追加、順次処理を学ぶ ななか十 inside press ◆ 22 スタイルに基づきます。既存のインスタンスに要素を追加するのではなく、要素が追加された新 素の追加や削除はできません。これは関数型言語の特徴である、「副作用」がないプログラミング なるのは、 List は「不変オプジェクト」であるという点です。例えば、一度作成した List への要 scala の List は、 Java の List と同様、順序を持つコレクションです。 Java の List と大きく異
3.2 クラスが簡潔に書ける セスできないパッケージプライベートですが、 Scala では何も記述しなければ public です。 リスト 7 Money クラス package money import j ava. util . Currency 行でクラスを定義できるわけです。このクラスを利用して、 100 円を表すコードを書くとリスト 9 記述も冗長です。この冗長さを取り除いて書いたのが、リスト 7 です。とても簡潔に、たった 1 るわけです。さらに、コンストラクタの引数とフィールドは一対一対応しているので、このような り、クラス宣言部とコンストラクタ宣言部をまとめて記述することで、簡潔で明瞭なコードを書け でもあります。この例では、コンストラクタの引数から val フィールドに代入しています * 6 。つま ストラクタ (primaryconstructor) と呼びます。また、このプロックはフィールド宣言のプロック し、 ( 1 ) のプロックがコンストラクタの処理プロックとなります。このコンストラクタを基本コン 記述したのがリスト 8 です。 Scala では、クラス名の後ろにコンストラクタの引数の仕様を記述 は、理解しにくいと思うので、段階を追って解説しましよう。リスト 7 のコードを省略しないで 円やドルなどそのお金の単位 ( 通貨単位 ) を表す Currency 型の currency です新。この説明だけで Money クラスには、二つの属性があります、 4 。金額の量を表す BigDecimal 型の amount と、 } 〃← currency = creny va1 amount = amnt class Money (amnt : BigDecima1 , creny : Currency) { / / ーー > 0 ) リスト 8 M 。 ney クラス ( 省略しないで書いたもの ) class Money (val amount : BigDecima1 , va1 currency : Currency) val money = new Money(100 , currency) / / プ 00 円 val currency = Currency. getlnstance ( " JPY" ) / / 円の通貨単位 リスト 9 100 円を表すコード のようになります。 println (money. amount) println(money. currency) / / プ 00 〃 JPY リスト 10 100 円と 50 円を加算した結果が 150 円になっているかを検証するテストコード。 Money クラスの plus メソッドはまだ存在しないので実行するとエラーになる * 4Scala ではクラス宣言だけでなく、フィールド宣言のデフォルトのアクセス修飾子も public です。 * 5 java. util.Currency クラスは通貨単位を表すクラスです。例えば、 val currency rency. getlnstance( ” JPY ” ) のようにすると円の通貨単位を取得できます。 、 6val のフィールドは Java の publicfinal フィールドに相当します。 Cur- ◆ 13 ななか十 inside press
トレイトは実装コードを書けるインタフェ def toReadab1e with Readab1eEmp10yeeRepository { with WritabIeEmpIoyeeRepository extends Emp10yeeRepositoryBase class Emp10yeeRepository / / 読み書き可能なリポジトリの宣言 with Readab1eEmp10yeeRepository extends Emp10yeeRepositoryBase class Emp10yeeReadOn1yRepository ース 6.4 print1n(emp2) / / EmpLoyee(), T の ) val emp2 = readOn1yRepos . load ( 1 ) val readOn1yRepos = repos . t0Readab1e println(emp) / / E 乙 ee ( 1 , T の val emp = repos . load ( 1 ) repos . save(Emp10yee(1, "KATO")) val repos = new Emp10yeeRepository def main(args : Array [String] ) { object RepositoryApp1ication { 〃アプリケーション本体 result result . entities 十十 = entities val result = new Emp10yeeReadOn1yRepository ◆ 29 ななか十 inside press 勧めします。 きっかけにして、 Scala 関連書籍やネット上のコンテンツを合わせて自分なりに学習することをお に体感することができます。こでは ScaIa の魅力のほんの一部しか紹介できませんが、これを 関数型が難しければ、従来からなじみのある命令型でプログラミングしても Scala の魅力を十分 しても敬遠しがちですが、まずは自分が理解した範囲から ScaIa を使い始めてもよいと思います。 ScaIa には次世代言語として様々な機能が実装されています。言語としての機能が多いとどう
2 表 2 Eclipse ユーザーのための IntelliJIDEA ショートカット一覧 Eclipse のショートカット IntelliJ の機能 InteIIiJ のショートカット 以下の三つの実行 ()pen R,esources Open Types Q uick Hierarchy Open Declarat ion Content Assist QtliCk Access Quick Assist(Assign to local variable) Quick Fix Eclipse の機能 Ctrl 十 1 Ctrl 十 2 , L Ct 日十 3 CtrI 十 Space F3 Ctrl+T CtrI 十 Shift 十 T Ctrl 十 Shift 十 R 一目でわかる「 HelloWorld 」 Show lntention Action lntroduce Variable.. Find Action Cornplete Code Type Hierarchy Open FiIes Open Class Alt 十 Enter CtrI 十 Alt 十 V Ctrl 十 Shift 十 A CtrI 十 Space Ctrl 十 B Ctrl 十 H Ctrl 十 N CtrI 十 Shift 十 N こで、 ScaIa プログラムの実行方法を整理しておきましよう。 scala には、 2 ユ対話型インタブリタで実行する 方法があります。 最初は、 Scala のコードをインタブリタで対話的に実行する方法です。この実行環境のこと 力して Enter キーを押すと、実行結果が対話的に確認できます。 「 scala> 」というプロンプトが表示されます。このプロンプトに続けて、 scala のプログラムを入 を REPL*I といいます。コマンドラインから scala コマンドを実行すると REPL が起動し、 Scala のセミコロン REPL は「 :quit 」あるいは「 : q 」と入力して Enter キーを押すと終了します。 He110 , Wor1d! scala> print1n("HeIIo, Wor1d! " ) 合はセミコロンを省略できます。ただし次のように、 1 行に複数の文を記述する場合は必要 Java では文の最後にセミコロン ( ; ) が必要ですが、 scala では 1 行に一つの文を記述する場 です。 message " He110 , println(message) Wor1d! " ・ * 1 Read Eval print Loop の略称 ななか十 inside press ◆ 7