社内Scala勉強会始めました
Twitter社の公開したScala教育用のコンテンツである Scala School! を使って社内Scala勉強会を始めました。
第一回は先週の11/2で、Basicsのページを進めました。
形式はみんなで顔を合わせつつ、同時にSkypeもつないでハマったところを共有しながら各自進める、という形式でやってみました。残念ながら僕は序盤に打ち合わせが入ってしまい抜けたのですが、一応全員Basicsのページは一通り進めたようです。
というわけでちょっと間が空いてしまいましたが、第一回で学んだことを簡単にメモします。
valとvar
変数の宣言の仕方が2通りです。valにすると再代入ができません。
scala> val two = 1 + 1
two: Int = 2
scala> two = 3
<console>:8: error: reassignment to val
two = 3
^
メソッド
色んな定義の仕方があってややこしい。
基本?
def addOne(m: Int): Int = m + 1
def メソッド名(仮引数: 仮引数の型): 返り値の型 = 処理内容
処理内容が複数の表現を含むときは、{}
で囲むことができる
def timesTwo(i: Int): Int = {
println("hello world")
i * 2
}
最後に評価した値が返り値となるのはrubyっぽい。
追記:上記、誤解でした。
@bleisさんに『最後に評価した値が戻り値になるわけではないです。それだと型を付けることができないので』と教えていただきました。以下のように書くとエラーになりました。
scala> def two: Int = {
| 2
| "string"
| }
<console>:9: error: type mismatch;
found : java.lang.String("string")
required: Int
"string"
^
ちなみにLLの感覚で文字列をシングルクォーテーションで囲むとエラー。Char型を表すのですね。
無名関数
scala> (x: Int) => x + 1
CoffeeScriptっぽい。もちろん変数に入れることも可能。
scala> val addOne = (x: Int) => x + 1
無名関数も{}
で囲むことができる。
scala> { i: Int =>
println("hello world")
i * 2
}
引数を取らない場合はかっこを省略できる。
scala> def three() = 1 + 2
scala> three
res3: Int = 3
部分適用
メソッドの引数のうち、一部だけを与えて新しいメソッドを作ることができる。
scala> def adder(m: Int, n: Int) = m + n
scala> val add2 = adder(2, _:Int)
scala> add2(3)
res19: Int = 7
まだ使いどころがよくわからない。
カリー化
scala> def multiply(m: Int)(n: Int): Int = m * n
scala> multiply(2)(3)
res0: Int = 6
scala> val timesTwo = multiply(2)(_)
scala> timesTwo(3)
res1: Int = 6
これも使いどころがよくわからない。
以下も同じような使い方ができると思うけど、使い分けは?
scala> def multiply(m:Int, n:Int) = m * n
multiply: (m: Int, n: Int)Int
scala> val timesThree = multiply(3, _:Int)
timesThree: Int => Int = <function1>
scala> timesThree(5)
res20: Int = 15
上記のメソッドは以下のようにしてカリー化できる。
scala> (multiply(_, _)).curried
res21: Int => Int => Int = <function1>
可変引数
def capitalizeAll(args: String*) = {
args.map { arg =>
arg.capitalize
}
}
次のrubyコードと動作は同じ。よく似てる。
def capitalizeAll(*args)
args.map {|arg|
arg.capitalize
}
end
クラス
class Calculator {
val brand: String = "HP"
def add(m: Int, n: Int): Int = m + n
}
scala> val calc = new Calculator
scala> calc.brand
res23: String = HP
scala> calc.add(4, 3)
res24: Int = 7
プロパティとメソッドの定義。
コンストラクタは特定の名前のメソッドを定義するのではなく、クラス内のメソッド定義の外側のコードがコンストラクタ。
class Calculator {
/**
* コンストラクタ
*/
val color: String = if (brand == "TI") {
"blue"
} else if (brand == "HP") {
"black"
} else {
"white"
}
// インスタンスメソッド
def add(m: Int, n: Int): Int = m + n
}
継承
class ScientificCalculator(brand: String) extends Calculator(brand) {
def log(m: Double, base: Double) = math.log(m) / math.log(base)
}
class EvenMoreScientificCalculator(brand: String) extends ScientificCalculator(brand) {
def log(m: Int) = log(m, math.exp(1))
}
書いていないけど、オーバーライドのときはoverrideとつけないといけない。
いい例が思いつかなかったので、処理内容が同一です。
class MyScientificCalculator(brand: String) extends ScientificCalculator(brand) {
override def log(m: Double, base: Double) = math.log(m) / math.log(base)
}
トレイト
PHPでも5.4から使えるあれですね。
trait Car {
var brand: String
}
class BMW extends Car {
var brand: "BMW"
}
インターフェイスとは違って抽象メソッドじゃなくても入れておけます。とか、複数のトレイトを使用する場合のこととか、そういうのはあとから出てくるのでしょうか。
型
型引数、とかジェネリクスとか言われると、Javaをやっていない身からするとちょっと厳しいです。
次のように、型引数を使用できます。
trait Cache[K, V] {
def get(key: K): V
def put(key: K, value: V)
def delete(key: K)
}
メソッドも型引数をつけられるそう。
def remove[K](key: K)
まとめ
後半の内容は、正直使いどころとかが理解できていません。
頑張って引き続き学んでいこうと思います。
実は去年にコップ本は一通り読んだのですが、残念ながらほとんど覚えていませんでした・・・。
一通りこのScala Schoolが終わったら読み直さないとダメかな。
ちなみに僕が持っているのは第1版です。