LL脳がscalaの勉強を始めたよ その17
Scalaコップ本の第7章に進みますよー、7章は組み込み制御構造についてですよー
組み込みの制御構造
Scalaの制御構造は以下の6つだけのシンプル思考デス
- if
- while
- for
- try
- match
- 関数呼び出し
Scalaは最初から関数リテラルを持っているので、高水準の制御構造はライブラリに蓄積しているらしいデス。うん、なんとなくPythonみたいな雰囲気がするな。ライブラリ云々の話は9章でやるみたいなので、またあとでー
Scalaは関数型指向なのでifとかfor,try,matchは値を返せるようになってるためにコードを単純化できるっぽいんだけども、そこら辺は実際の制御式を見ていきましょうかねー
if式
うん、ifですな。とりあえず命令型っぽいコードを書いて後から直すよー
// 適当な条件で値が入ったり入らなかったり val hoge = "hoge" // if式開始 var result = "default" if(!hoge.isEmpty) result = hoge
関数型に書き換えてみましょうー
上の式でダメダメなvar使っている部分をvalにするのが関数型のトレンドデス。あとifは式なので欲しい値resultに直接ぶっこんでしまいましょー
// 適当な条件で値が入ったり入らなかったり val hoge = "hoge" // if式開始 val result = if(!hoge.isEmpty) hoge else "default"
無理やり一行にまとめた感もあるけども超すっきりじゃないかしら?
結果値resultはvalなので書き換えられる心配もないし、この形式であれば等式推論をサポートしやすくなるので素晴らしいのデス
等式推論
valで定義される変数とその計算式は同じものとみなせることを等式推論というらしいです。条件は式に副作用が無いことですねー。等式推論が使えると一時的に定義した変数を使わずに計算式を用いることができるようになるのですな。
例えば下の処理は上の式の結果値resultをprintln(result)したのと同じ結果になりマス
// 適当な条件で値が入ったり入らなかったり val hoge = "hoge" // 等式推論使って表示しますよー println(if(!hoge.isEmpty) hoge else "default")
resultっていう変数定義すらいらなくなるので使い捨ての式がシンプルになるのね、なるほど
とりあえず
valつかえ、valってことね
whileループ
繰り返しー
前の章でやったような最大公約数を求める処理のwhile版をサンプルに書いてみます
def gcdLoop(x: Long, y:Long):Long = { var a = x var b = y // whileでユークリッド互除法をやるっす while(a != 0){ val temp = a a = b % a b = temp } // 値を返すよー b }
実行結果はこんな感じ
scala> gcdLoop(3,4) res7: Long = 1 scala> gcdLoop(123,24) res8: Long = 3
うん、上手くいってますねー
do-whileも使えますよー
標準入力を読み出すサンプルメソッドデス
def readMethod() = { var line = "" do { line = readLine() println("Read: " + line) }while(line != "") }
ちょっとわかりにくいけど結果ですよー、標準入力を取得して空行のときに終了してます
scala> readMethod Read: ほげほげ Read: ふがふが Read:
whileとdo-whileはUnit型
意味のある結果値が得られないwhileとdo-whileは式ではなく「ループ」でありマスので、結果値型はUnit型になるみたいデス。
Unit型の値
ちなみにUnit型は値()をとるので、値を取らないJavaのvoid型とは違うんだぜーのお話
雰囲気のわかるサンプルコードを書いてみますよ
// printlnするだけのUnit型のメソッド scala> def hi(){ println("hi") } hi: ()Unit // 結果値が()と等しいことがわかりますなー scala> hi() == () hi res7: Boolean = true // 引数省略してみてもいけますね、蛇足ですがー scala> hi == () hi res8: Boolean = true
なので、こんな処理はエラー出ますよ
def readMethod() = { var line = "" // String型にUnit型を代入してます while((line = readLine()) != "") println("Read: " + line) } } // エラーメッセージ // Unit型とString型の!=比較は必ずTrueになるよ!いいの?(意訳) <console>:6: warning: comparing values of types Unit and java.lang.String using `!=' will always yield true while((line = readLine()) != "")
Scalaでは”代入という式”の結果値がUnit型になるので、例えば上の式だと永久にループしてしまうので危険デス
ちなみに雰囲気をつかむために書いてみたこういう単純なのでもダメでしたー
scala> var hoge = "" hoge: java.lang.String = // 代入式の等価評価はダメですねー scala> (hoge = "huga") != "" <console>:6: warning: comparing values of types Unit and java.lang.String using `!=' will always yield true (hoge = "huga") != "" ^
関数型なら再帰でしょ?
関数型のアプローチだと再帰処理にしましょーってことで、最初に出てきた最大公約数を求める処理を再帰で書いてみますよー
def gcd(x:Long, y:Long): Long = if(y == 0) x else gcd(y, x % y)
うん、前の章で似たようなのを作ったっすね
さて実行してみると、無事処理が行われますな
scala> gcd(3,4) res12: Long = 1 scala> gcd(123,24) res13: Long = 3
ループに関して行間を読んでみた
関数型で書きたかったらループ使うなよ!(`・ω・´)
…間違ったメッセージを受信した可能性もあるので、自己責任で(・∀・)