Scalaアンチパターン
過去に自分が書いたScalaコードのアンチパターンをまとめました。
定数名が大文字
// ダメ val MAX = 100 val MIN = 1 val HOGE_HOGE = "hogehoge" // 良い val Max = 100 val Min = 1 val HogeHoge = "hogehoge"
map + getOrElse
map(???).getOrElse(???)は冗長です。foldを使ってシンプルに記述することができます。
// ダメ object Main extends App{ val option = Some("hoge") val str = option.map(_.toUpperCase).getOrElse("") println(str) }
// 良い object Main extends App{ val option = Some("hoge") val str = option.fold("")(_.toUpperCase) println(str) }
returnを使う
returnはScalaらしくないので使うべきではありません。
Scalaの主な構成要素は式です。return文は異物感がします。
object Main extends App{ def hoge(isHogeHoge: Boolean): String = { if(isHogeHoge) return "hogehoge" return "" } println(hoge(true)) }
get
option.getとすると例外が発生する可能性があります。getOrElseやmapで代用すべきです。
1文字の変数名"l"
Either型の値に対してmatchを使う場合、Leftにマッチさせる変数名に"l"(エル)を使いたくなる場合があると思います。
しかし、"I"(アイ)や"1"(イチ)と区別しづらくなるのでダメだと思います。
either match { case r: Right[???, ???] => ??? case l: Left[???, ???] => ??? }
他にも、0(ゼロ)とO(オー)も識別しずらいと思います。スコープが短いと、使いたくなるのですが。。。
Either
Eitherはモナドでないので使いづらいです。
EitherよりOptionを使うべきです。
publicメソッドに戻り値の型を書かない
publicメソッドは外部のクラスから使われるので戻り値の型は書くべきです。
// ダメ def hoge(fuga: String) = ??? // 良い def hoge(fuga: String): String = ???
冗長な型アノテーション
// ダメ val x: HashMap[Int, String] = new HashMap[Int, String]() // 良い val x = new HashMap[Int, String]() val x: Map[Int, String] = new HashMap()
コップ本には、次のようなことが書かれています。
一般にドキュメントが役に立つのは、簡単にはわからないことを示しているときだ。
型が簡単にはわからないときに、型アノテーションをつけるべきです。
タプルで_1とか_2を使う
tuple._1とtuple._2とすると、意味がわかりにくいです。パターンマッチを使った方が意味がわかりやすいと思います。
object Main extends App{ val prefectureCaptals = List( ("滋賀", "大津"), ("三重", "津"), ("兵庫", "神戸") ) // ダメ prefectureCaptals.map( pc => println(pc._1 + " : " + pc._2) ) // 良い prefectureCaptals.map(_ match { case (prefecture, captal) => println(prefecture + " : " +captal) }) // 良い val (prefecture, capital) = prefectureCaptals.head println(prefecture + " : " + capital) // 良い for((prefecture, capital) <- prefectureCaptals){ println(prefecture + " : " + capital) } }
foldLeftよりreduceLeft
初期値が不要な場合はfoldLeftではなく、reduceLeftを使うべきです。
object Main extends App{ val list = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) // ダメ val sum1 = list.foldLeft(0){_ + _} // 良い val sum2 = list.reduceLeft{_ + _} }