関数型のメリット
- 副作用の排除
副作用とは
ある機能がコンピューターの(論理的な)状態を変化させ、それ以降で得られる結果に影響をあたえることをいう
- 変数への値の代入
- データ構造を直接変更する
- オブジェクトのフィールドを設定する
- 例外をスローする、またはエラーで停止する
- コンソールに出力する、ユーザ入力を読み取る
- ファイルを読み取る、ファイルに書き込む
- 画面上に描画する
純粋関数
副作用を持たない関数
メリット
- 宣言的な記述なため、簡潔に書けることが多く、関数の仕様を理解しやすい
- 副作用がないため、形式的な証明がし易い
- 関数の評価結果がコンテキストに依存しないため、テストがし易い
- コンテキストに影響を与えないため、関数を組み合わせて利用しても相互に影響しない
インストール
scalaenvを使ったインストール
scalaenvのインストール
$ git clone git://github.com/mazgi/scalaenv.git ~/.scalaenv
$ echo 'export PATH="${HOME}/.scalaenv/bin:${PATH}"' >> ~/.bashrc
$ echo 'eval "$(scalaenv init -)"' >> ~/.bashrc
scalaのインストール
$ scalaenv install -l
$ scalaenv install scala-2.11.7
$ scalaenv versions
基本構文
コメント
// コメント
/* これもコメント */
/**
* コメントです
*/
セミコロン
セミコロン(;
)は省略可能
変数
var 変数名:型 = 値
型については、型推論であるため省略可能
var num:Int = 1
var str:String = "abc"
var short:Short = _ // _で初期値が設定される
定数
val 定数名:型 = 値
val NUM:Int = 1
val STR:String = "abc"
代表的な型
name | description | default value |
---|---|---|
Boolean | 真偽値 | false |
Char | 2byte文字列 | '\0' |
String | 文字列 | null |
Short | 整数(16bit) | 0 |
Int | 整数(32bit) | 0 |
Long | 整数(64bit) | 0 |
BigInt | 任意精度整数 | null |
Float | 浮動小数(32bit) | 0.0 |
Double | 浮動小数(64bit) | 0.0 |
BigDecimal | 任意精度固定小数 | null |
Symbol | シンボル(文字の前にシングルクォート | null |
制御文
if
if (true) 1 else 2
while
条件式はBoolean型である必要がある
while (true) A
for
for (s <- Array("a", "b", "c")) println(s)
match
他の言語でいわゆる、swich-case文のイメージ
var one = 1
one match {
case 1 => println("one")
case 2 => println("two")
case _ => println("other")
}
関数
def 関数名 (引数名 : 引数の型) : 戻り値の型 = {}
def append_ten(num : Int): Int = {
return num + 10
}
return
は省略可能で、省略した場合は最後に評価した式の値が戻り値として返される
戻り値の型と{}も省略可能
1行で記述
def append_ten(num : Int) = num + 10
クラス・メソッド
コンストラクタ
// class名(コンストラクタのパラメータを宣言)
class User(_name : String) {
def name = _name
}
var user = new User("Tom")
println(user.name) // Tom
フィールド
フィールドはvar
かval
で定義する
var
ではsetter/getterの提供、val
ではgetterのみの提供
class User(_name : String, _age : Int) {
var name = _name
val age = _age
}
var user = new User("Tom", 23)
println(user.name) // Tom
println(user.age) // 23
user.name = "Bob" // nameは"Bob"に更新される
user.age = 14 // val定義なのでエラーになる
アクセス修飾子と継承
class User(_name: String, _age: Int) {
val name = _name
val age = _age
def agree = println("Hi, I'm " + name)
def how_old = println("I'm " + fudge_the_count)
protected def real_age = age // protected メソッド
private def fudge_the_count = age - 5 // private メソッド
}
// extendsキーワードで継承
class Profile(_name: String, _age: Int) extends User(_name: String, _age: Int) {
// 親クラスのメソッドをオーバーライド
override def agree = println("Hi, I'm " + name + ". I'm going to be " + real_age + " this year")
}
var user = new User("Tom", 42)
user.agree
user.how_old
var profile = new Profile("Tom", 42)
profile.agree
オブジェクト
シングルトンオブジェクトの作成 = Javaのstaticと同等の役割
mainメソッド
実行時の処理を実装する
object Obj {
def main(args: Array[String]) {
println("Hello, World")
}
}
コンパニオンオブジェクト
クラス名と同じ名前をつけたオブジェクトのこと
共通の操作・処理を扱う
class Sample {
}
object Sample {
}
ファクトリー
class Sample private(a: Int) {
protected var n = a
}
object Sample {
def apply(a: Int) {
new Sample(a)
}
}
Sample.apply(123)
Sample(123)
トレイト(Trait)
機能の実装が行えるインタフェースのようなもの
Javaのインタフェースと同様、mix-inすることが出来る
trait Agree {
def en = println("Hello, World")
}
trait Body {
}
/* mix-in */
class User extends Agree with Body
タプル(Tuple)
複数のデータを格納できるコンテナ型。違う型でも格納できる。
val t = (1, "abc", 2)
22個までがタプルに格納できる限界数
コレクション
Seq
要素を並べて管理するコレクション
var seq = Seq(1, 2, 3)
// 取得
println(seq(0))
// loop
seq.foreach { println }
Map
キーを元に値を取得するコレクション
var map = Map("key" -> "val")
// 取得
println(map("key"))
// 追加
map += ("key2" -> "value")
例外処理
try {
func()
catch {
case e: IOException => ...
finaly {
}
try, catchはそれぞれ値を返すが、finalyは返さない
Option
Optionは値がない可能性を型で表現している
スレッド
JavaのThread等そのまま使えるが、Actorを使うことが多いらしい