scalaの組み込み制御構文は少ししかない。
if, while, for, try, match と function call
便利な構文を組み込む代わりに、ライブラリとして実装している。
制御構文も値を持つ。
関数型言語的なアプローチを取っている。
コードを簡素化できる。
中間変数を減らせる。
バグを減らせる。
あるブランチの戻り値設定忘れを減らせる。
7.1 If expressions
ifが値を持つことで中間変数を減らして読みやすくなる。
また、varを減らしてより関数型的に書けるようになる。
等式推論(equational reasoning)のサポート
名前とその表現が置き換え可能であると言う事。
?? 遅延評価や並列実行をしやすくする??
refactoringしやすくなる。
7.2 While loops
whileとdo-whileのloop構造がある。
意味のある値を返さない。式(expression)ではない。
実行後の値は():Unitになる。
Unit型の値は()のみ。
値があるのでjavaのvoidと違って比較なども可能。
(while (false) {}) は常にtrueになる。
常にtrueになるとのwarningは出るが。。。
** 逆に例外が投げられないので意図していない動作を見逃す可能性あ
?? この辺りのエラーが出にくい仕様が欠点かもしれない??
?? 静的だが動的型付けの思想が入っている? なるべく実行しようとする?
代入メソッド=の戻り値も():Unitになる!!
代入された値が評価結果になるjavaやcと異なる。注意が必要
a = 1, a += 1 の結果は()
(a = 1) == 1 はfalse。しかもwarningが出る。
whileの仕様は関数型的ではないのであまり推奨はしない。
命令型的な書き方に慣れている人のために残してある。
recursiveで代用できる。
7.3 For expressions
Iteration through collections
for (i <- 1 to 4) ...
"i <- 1 to 4" syntax は generator
1 to 4 は Range type
1 until 4 だと 1, 2, 3
iはvalでイテレーションの度に生成、初期化される。
ループカウンタを使うやり方より優れている。
初期値、終了値、インクリメントの方法など気にしなくて良い。
Filtering
for (i <- 1 to 4 if i % 2 == 0; if i != 3) body
if clauseをつけることでbodyの実行対象をfilter出
ifは;で区切れば複数書ける。and条件。
改行を入れる場合でも;必要な(事がある)ので注意が必要。
()ではなくて{}を使えば;の代わりに改行でOK。
ifのconditionは()不要。
Nested iteration
for (
i <- 1 to 4 if i % 2 == 0;
j <- 10 to 14 if j != 13
) println(i + " " + j)
generator, filterの組を複数書くことで多重ループを作れる。
上が外側のループで下が内側のループ。
区切りの;は改行しても省略出来ない。{}
Mid-stream variable bindings
for {
i <- 1 to 10 if i % 2 == 0
k = i * 2 if i % 3 == 0
j <- 11 to 20 if j != 13
} println(i + " " + k)
forの中で変数束縛も出来る。valと同等で不変の変数。
?? ifの前にも後ろにも置ける??
?? 内包表現に記載できるものの条件は??
Producing a new collection
for clauses yield body
bodyの評価結果をcollectionにして返す。
どういうcollectionになるかはgeneratorに依
bodyの前にyield修飾子が必要。bodyの中ではだめ。
Range typeだとVector()になる。
StringだとVector, ArrayはArray, ListはList...
?? どういうcollectionのかよくわからない。
?? for (4 <- 1 to 4) でもエラーにならない。一回しか回らない。
?? for (), for {}の使い分けが分からない。
?? 関数定義しないでインラインで書けば型推論が使える。
?? パラメータの型指定必須なのが使いにくい??
?? 型パラメータを使えばいい??
7.4 Exception handling with try expressions
scalaのexceptionは他の言語と似ている。
exceptionが発生すると処理を中断して上位に戻る。
exceptionをhandleしなかったらその更に上位に伝
Throwing exceptions
throw new IllegalArgumentException
javaと同じ
scalaではexceptionも戻り値を持っている。
戻り値の型はNothing
if式の片側がthrowで戻り値の型がNothingになる場
この場合はif式の方はthrowが無い方の枝の型になる。
?? Nothingは評価されることがない型??
?? Unitは評価されることがありえるので違う??
Catching exceptions
try {...} catch { case ex: xxException => }
他の言語と同じようにtry-cacth式を使う。
catch節はパターンマッチングのシンタックスを使う。
?? scalaではjavaと違って例外の補足やthow節での宣言
?? @throwを使えばjavaと同じように出来る? Section 29.2参照。
The finally clause
try {...} finally {...}
他の言語と同じように例外の有無と関係なく実行される。
loan patternを使えば同様のことが簡素に書ける。
Yielding a value
try-catch-finallyも値を返す。
finallyでは副作用のある後処理のみをすべきで、
try { 1 } finally { 2 } は1を返すが、
try { return 1 } finally { return 2 } は2を返す。
?? どうして??
これは自然には理解できないので、
7.5 Match expressions
値 match { case パターン => 式; case ... }
javaのswitch-caseに対応するが、
任意のパターンが使える。整数だけではなくて。
Match expressions自体も値を返す。
_ は完全に値が分からない時に使うpalceholder
case _ ... => ... で全てにmatchするdefaultとして使える。
breakの記載は不要で、falling throughしない。
** パターン書き方は多彩で記述力が高い。Chapter 15参照。
7.6 Living without break and continue
scalaにはbreakやcontinueがない
関数リテラルと相性が悪いから。
この点では関数型に多少傾いている。
再帰呼び出しや関数リテラルを使った方が簡素に書ける。
末尾再帰は最適化されるのでスタックの消費は心配要らない。
7.7 Variable scope
nested scopeで外側と同じ名前を使えるところ以外はjavaと同じ
shadow
shadowは混乱の元なのでなるべく使わない方が良い。
{}が始まるたびに新しいスコープが作られる。
interpreterではコマンドを打つたびに{}
したがって、
7.8 Refactoring imperative-style code
side effect, while loop, varの使用をやめてfunctional styleにする。
printの変わりに結果を文字列で保存したほうが単体試験がし
print関数を別の関数で置き換えたりするstubの作成も不
helper function
インラインでも構わないが、読みやすくするために定義している。
すぐ側の関数を補助するための関数。
?? これを定義する時にパラメータの型指定が面倒だと思うけど??
7.9 Conclusion
制御構造は最小限。
値を持つので関数型スタイルにも使える。
関数リテラルと言う最も強力な特徴は次章で説明。
0 件のコメント:
コメントを投稿