Skip to content

Instantly share code, notes, and snippets.

@nenono
Last active August 29, 2015 14:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nenono/b1c63260b412a906bf7d to your computer and use it in GitHub Desktop.
Save nenono/b1c63260b412a906bf7d to your computer and use it in GitHub Desktop.
Scalaで基本的な型を定義する
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