変数多いぅぉ・・・try catchやifが値を返せばretValとかいらないのに・・・
という「Javaコードを見るとscalaで書き直したい病」が発病したので(・ω・`)
元のJavaコード↓
@Override public int compare(Player o1,Player o2) { float o1A, o2A; int retVal; if(o1.getId() == o2.getId()) return 0; if(o1.hasRole(Player.Roles.Batter)){ try{ o1A = o1.asBatter().getAverage(); }catch(NotEnoughAtBatsException e) { o1A = 0.0f; } } else o1A = 0.0f; if(o2.hasRole(Player.Roles.Batter)) { try { o2A = o2.asBatter().getAverage(); } catch (NotEnoughAtBatsException e) { o2A = 0.0f; } } else o2A = 0.0f; if(o1A < o2A) retVal = -1; else if( retVal = 1; else if(o1.getId() < o2.getId()) retVal = -1; else retVal = 1; return retVal; }
書き直したscalaコード*1
override def compare(o1:Player,o2:Player):Int = { //処理重複してたから、ローカル関数にしてみた //try catch や、if自体が値を返すから、変数がいらなくなる def getAverage(p:Player):Float = { if(p.hasRole(Player.Roles.Batter)){ try{ p.asBatter.getAverage }catch{ case _:NotEnoughAtBatsException => 0.0f } } else 0.0f } if(o1.getId == o2.getId){ 0 }else{ // matchも式であり、値を返すから、ここでも一時変数がいらなくなる ( getAverage(o1) compare getAverage(o2) ) match { case 0 => o1.getId compare o2.getId case x => x } } }
こんな感じで、scalaにちょっと慣れれば、「ifやtry catchそれ自体が式であり、値を返す」*2ので、変数がいらなくなります。
変数がないと
- 初期化の忘れとか、そういうこと自体をそもそも考えなくてよくなる
- どこで使われて、スコープどこまでなのか?を考えなくてよくなるので、コードを読むときに読みやすい
っていうところが利点ですかね、個人的な感覚としては。
matzがよく「名前重要」っていいますが、
たいして意味のないものに名前をつける
って結構めんどくさいというか、変数に名前をつける必要がないと、
大事なものにだけ名前をつけられる
ので、よりわかりやすくなる(?)というのがポイントです。
ローカル関数についてですが、これも別にprivate(でstatic)な関数を定義すればJavaでも同じ事ができます。が、その場合
スコープがclassの中全体になる
のにたいして、ローカル関数だと
スコープがそのメソッドの中だけ
になります。
class内のprivateな関数にしたとしても、やってることは同じになりますが、ローカル関数を使うことによって、
この関数はこのメソッドからしか使用しない
という意図を表現することができます。
はぁ何言ってんの?そんな細かいことどうでもいいよ(・д・´)
と言われればまぁそれまでなんですが、個人的には、scalaのこういう細かいところが気に入ってます。
そして、
getAverage(o1) compare getAverage(o2)
と
o1.getId compare o2.getId
の部分ですが、IntやFloatがそれぞれ、implicitにRichIntやRichFloatというものに変換されて、そのcompareというメソッドが呼ばれてます。
このIntからRichIntに変換される関数が、Predefに定義されていて、デフォルトで使えるので、こんな感じでちょっと短く書けます。
*1:よく見ると、if(o1.getId == o2.getId) で、0を返す部分もそもそもいらなくなる・・・けど、動作的に余計なことするから、このままでいいのかなぁ・・・?0返してるのは、同じオブジェクトの場合を考慮してるんだろうけど、その場合って結局getIdが同じ値返すことになるから、o1.getId compare o2.getIdの部分で0が返る。ん〜すごく微妙なところ・・・
*2: 言葉の使い方おかしいのを指摘された(?)のでちょっと修正しました。ありがとうございます