Last active
August 29, 2015 14:17
-
-
Save nenono/b1c63260b412a906bf7d to your computer and use it in GitHub Desktop.
Scalaで基本的な型を定義する
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package object DataTypes { | |
// クラス定義は1ファイルに複数書き並べることもできます | |
// クラスのインナークラスとしても書けます(Javaと同様、外部クラスへの参照を保持します)。 | |
// package objectは、普通のシングルトンオブジェクトのように書けて、利用側でのimport方法がパッケージの形式になります。 | |
// --------------------------------------------------------------------------------- | |
// immutable data | |
class Person(val name: String, val birthYear: Int) {// コンストラクタで同時に読み取り専用プロパティを定義 | |
// その他コンストラクタ | |
def this() = { | |
this("nanashisan", 0) // プライマリ・コンストラクタの呼び出し | |
} | |
// メソッド | |
def sayHello = { | |
println(s"Hello. I am ${name}.") | |
} | |
def getAge(thisYear: Int) = thisYear - birthYear | |
} | |
def immutableDataTest = { | |
println("--immutableDataTest--") | |
val p = new Person("John", 1997) | |
println(s"name:${p.name} birth:${p.birthYear}") | |
p.sayHello | |
println(s"age:${p.getAge(2015)}") | |
} | |
// --------------------------------------------------------------------------------- | |
// mutable data | |
class Hitpoint(private var value_ : Int) {// コンストラクタで同時に可変プロパティを定義 | |
// 読み取り専用プロパティを追加定義 | |
val maxValue = value // 固定値 | |
def value = value_ // getter | |
// メソッド | |
def -=(arg: Int) = { | |
if (arg > value) | |
value_ = 0 | |
else | |
value_ -= arg | |
} | |
def isDead = value <= 0 | |
} | |
def mutableDataTest = { | |
println("--mutableDataTest--") | |
val h = new Hitpoint(100) | |
println(s"hitpoint:${h.value}") | |
h -= 20 | |
println(s"hitpoint:${h.value} dead?:${h.isDead}") | |
h -= 255 | |
println(s"hitpoint:${h.value} dead?:${h.isDead} maxValue:${h.maxValue}") | |
} | |
// --------------------------------------------------------------------------------- | |
// 継承, ジェネリック型 | |
// 抽象クラスはabstractキーワードで定義します | |
// ジェネリッククラスやtraitは、[]の中に型変数を記述します | |
// 型の中身が無い場合は波括弧 { } も省略できます | |
abstract class Item[A](val id :A, val label: String) | |
trait Clickable{ | |
def onClick : Unit // = を付けない defは抽象メソッド | |
} | |
trait Selectable[A] { | |
val id : A // 抽象getterプロパティ | |
def onSelected { // 抽象メソッドのデフォルト実装 | |
println(s"item(${id}) selected!") | |
} | |
} | |
// classを継承する場合はextends, traitの場合はwithで実装、但しtraitしか使わない場合、その一つ目はextendsと書きます | |
// 親クラスのコンストラクタに渡す引数はextendsのところに書きます(型推論が利く場合は型変数省略可) | |
class ListItem(id:Int, label:String) extends Item(id, label) with Clickable with Selectable[Int] { | |
// overrideで親クラスのメソッド上書き。但し上書き元メソッドが抽象メソッドの場合はoverrideキーワードの省略可。 | |
override def onClick = println(s"${label}(${id}) clicked!") | |
override def onSelected = println(s"${label}(${id}) selected!") | |
} | |
def inheritanceTest = { | |
println("--inheritanceTest--") | |
val items = List(new ListItem(1, "aaa"), new ListItem(2, "bbb"), new ListItem(3, "ccc")) | |
items.foreach(_.onSelected) | |
items.foreach(_.onClick) | |
} | |
// --------------------------------------------------------------------------------- | |
// 代数的データ型は、クラスの継承関係で再現します。 | |
// インターフェース定義はtraitで。型引数TDataを持ちます。 | |
// sealedキーワードは継承可能な場所を同一ファイルに限定します。それによりパターンマッチの網羅性が検査されるようになる、とか。 | |
sealed trait Operation[TData] | |
// ジェネリックなcase classを定義。 | |
// case classは equals, hashCode, toString, unapply(パターンマッチ用のメソッド)等が自動実装されます。 | |
// 参考: [scalaのcase class - scalaとか・・・](http://d.hatena.ne.jp/xuwei/20101005/1286303814) | |
case class Submit[TData](data: TData) extends Operation[TData] | |
// case classその2 | |
case class Cancel[TData]() extends Operation[TData] | |
def algebraicDataTypeTest = { | |
println("--algebraicDataTypeTest--") | |
// Operationのどちらかを返す関数 | |
def getOperation(message: String = null): Operation[String] = { | |
if (message == null) Cancel[String] // この辺り、型の明示がちょっと面倒かも | |
else Submit(message) | |
} | |
val op1 = getOperation("hello") // ジェネリッククラスのインスタンス生成も、型推論は上手くやってくれるようです | |
val op2 = getOperation() | |
List(op1, op2).foreach((x: Operation[String]) => { | |
x match { | |
case Submit(message) => println(s"submitted:${message}") | |
case Cancel() => println(s"canceled") | |
} | |
}) | |
} | |
// --------------------------------------------------------------------------------- | |
// 列挙型は、シングルトンな代数的データ型として表現します | |
// 参考: [ScalaのEnumerationは使うな - Scalaで列挙型を定義するには | Scala Cookbook](http://xerial.org/scala-cookbook/recipes/2012/06/29/enumeration/) | |
sealed abstract class ErrorCode(val code:Int)// abstract classはコンストラクタを持てる | |
case object E0001 extends ErrorCode(1) | |
case object E0002 extends ErrorCode(2) | |
case object E0003 extends ErrorCode(3) | |
def enumTest = { | |
println("--enumTest--") | |
println(s"ErrorCode: ${E0001.code} ${E0002.code} ${E0003.code}") | |
} | |
// --------------------------------------------------------------------------------- | |
def main(args: Array[String]) { | |
immutableDataTest | |
mutableDataTest | |
inheritanceTest | |
algebraicDataTypeTest | |
enumTest | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment