3分で掴むScalaのコツ
Posted on 2014-03-08 by takezoux2ある程度Scalaの基本文法を知っている+オブジェクト指向言語を理解している人向けです。
独断と偏見で使用頻度の高いものをピックアップしているので、人によって所感は違うかもですが、ご容赦下さい。
1. 関数型=関数がファーストクラス+副作用が無い(ようにかける) であることを心がける
Scalaは、オブジェクト指向言語であるとともに、関数型言語でもあります。
java likeに書くことは出来ますが、関数型的にかけるとかっこいい、テストしやすい、わかりやすい、などいいことずくめです。
val と varの違い
変数の宣言をするときに、valとvarの2種類のキーワードが有ります。
違いは、valは変数を定義した後再代入不可、varは再代入可能です。
Scalaでは基本的にvalを使うようにしましょう。副作用がないプログラムをかけるようになります。
val a = 1
var b = 2
a = 334 // Error!
b = 2183 // OK!
ラムダ式
ようは簡単に関数が定義できる機能です。
メソッドに関数を渡す時によく利用します。
val nums = List(1,2,3,4,5)
val evens = nums.map( i => i * 2) // <- i = i * 2がラムダ式
関数を引数に渡せる
関数がファーストクラスなので、関数を引数に取るメソッドを定義できます。
def printTime( format : Int => String) = {
(1 to 12).foreach( hour => printn(format(hour)) )
}
printTime( hour => hour + "時です") // 1時~12時が出力される
printTime( hour => s"${hour}:00") // 1:00 ~ 12:00が出力される
2. Listのメソッドを覚える
Scalaは標準ライブラリが非常に強力です。他にも、便利なクラスはいろいろ有りますが、特にListのメソッドは使用頻度が高いので何があるかを把握しておきましょう。特に、次のメソッドはマストラーンです。
foreach
要素を一つ一つ処理していきます。
val list = 1 :: 2:: 3 :: Nil
list.foreach( i => println(i) )
map
要素を変換し、新しいリストを返します。
val list = 1 :: List(2,3)
val odds = list.map(i => i * 2 - 1)
filter
trueを返した要素だけを取り出したリストを返します。
val list = (0 to 100).toList
val evens = list.filter( _ % 2 == 0)
groupBy
返した要素をKeyとしてグルーピングしたMapを返す
val objects = List("Apple","Apache","Banana","Bash","Scala","Stash")
val groupByInitial = objects.groupBy( s => s(0))
/* 中身はこんな感じになります
Map(
'A' -> List("Apple","Apache"),
'B' -> List("Banana","Bash"),
'S' -> List("Scala","Stash")
)
*/
※Mapは連想配列のことです。
3.パターンマッチング
Scalaでは、他の言語でのswitchみたいなものが非常に強力になっています。これを使わなければScalaとは言えないレベルです。
Case class
Scalaのパターンマッチングを非常に強力してくれる機能です。だいたい次のように使います。
trait Exp
case class Add( a : Int, b : Int) extends Exp
case class Sub(a : Int , b : Int) extends Exp
def calc( exp : Exp) = {
exp match{
case Add(a,b) => a + b
case Sub(a,b) => a - b
}
}
calc(Add(1,2)) // return 3
calc(Sub(4,2)) // return 2
Option型
Scalaは、nullチェックは基本使いません。nullが入りうる可能性がある変数は、変わりにOption型でラップしパターンマッチングやforeachなどで値を取り出します。
def login( nameOp : Option[String]) = {
nameOp match{
case Some("ぽこ") => println("ぽこたんインしたお")
case Some(name) if name.startsWith("悟") => printnl(s"オッス、オラ${name}")
case Some(name) => println(s"${name}さんがログインしました")
case None => println("中に誰もいませんよ?")
}
}
login(Some("ぽこ")) // "ぽこたんインしたお"が出力
login(Some("悟空")) // "オッス、オラ悟空"
login(Some("太郎")) // "太郎さんがログインしました"
login(None) // "中に誰もいませんよ?"
だいたい、このあたりのことを気を付けて書けば、なんかScalaっぽいコードになります。