S-JIS[2013-06-08] 変更履歴
ScalaのType Dynamicのメモ。
DynamicはScala2.10で導入されたトレイト。
このトレイトをミックスインして特定のメソッドを記述すると、フィールド操作のようなコーディングで値の更新・取得が出来る。
(updateやapplyメソッドを実装すると特殊な記法が出来るのと同様)
(Dynamicトレイト自体には何も実装されていない)
Dynamicを使うにはdynamicsパッケージをインポートしておく必要がある。
import scala.language.dynamics
| 例 | 備考 |
|---|---|
class MyMap extends Dynamic {
val map = Map("abc"->123, "def"->456, "ghi"->789)
def selectDynamic(key: String): Int = {
map.getOrElse(key, 0)
}
}
scala> val m = new MyMap
m: MyMap = MyMap@13882c0
scala> m.selectDynamic("abc")
res12: Int = 123
scala> m.abc
res13: Int = 123
scala> m.zzz
res14: Int = 0
scala> m.def <console>:1: error: identifier expected but 'def' found. scala> m.`def` res15: Int = 456 |
Dynamicトレイトを継承して selectDynamicというメソッドを実装すると、 フィールド取得の形式( obj.field)でselectDynamicメソッドを呼べる。 なお、フィールド名を指定する部分では |
class MyProperties extends Dynamic {
val map = scala.collection.mutable.Map.empty[String, Any]
def updateDynamic(key: String)(value: Any): Unit = {
map(key) = value
}
def selectDynamic(key: String): Any = {
map.getOrElse(key, "")
}
}
scala> val p = new MyProperties
p: MyProperties = MyProperties@3d2429
scala> p.abc = 111
p.abc: Any = 111
scala> p.updateDynamic("def")(222)
scala> p.abc
res22: Any = 111
scala> p.selectDynamic("abc")
res23: Any = 111
scala> p.zzz
res24: Any = ""
|
updateDynamic(とselectDynamic)メソッドを実装すると、 フィールド設定・取得の形式でメソッドが呼べる。 |
class MyArray extends Dynamic {
val a = Array("a1", "a2", "a3")
val b = Array("b", "bb", "bbb")
def applyDynamic(key: String)(index: Int): String = {
key match {
case "a" => a(index)
case "b" => b(index)
case _ => ""
}
}
}
scala> val arr = new MyArray arr: MyArray = MyArray@19e2223 scala> arr.a(1) res29: String = a2 scala> arr.b(1) res30: String = bb scala> arr.z(0) res31: String = "" |
applyDynamicメソッドを実装すると、 配列の形式( obj.field(index))でメソッドが呼べる。 |
class MyArray extends Dynamic {
val a = Array("a1", "a2", "a3")
val b = Array("b", "bb", "bbb")
def selectDynamic(key: String) = new {
def update(index: Int, value: String): Unit = {
key match {
case "a" => a(index) = value
case "b" => b(index) = value
case _ =>
}
}
}
def applyDynamic(key: String)(index: Int): String = {
key match {
case "a" => a(index)
case "b" => b(index)
case _ => ""
}
}
}
scala> val arr = new MyArray arr: MyArray = MyArray@650952 scala> arr.a(1) res35: String = a2 scala> arr.a(1) = "zzz" scala> arr.a(1) res37: String = zzz |
selectDynamicメソッドを実装して updateメソッドを持つクラスを返すと 配列への代入の形式も扱うことが出来る。 |
class MyName extends Dynamic {
val map = scala.collection.mutable.Map.empty[String, Map[String, Int]]
def applyDynamicNamed(key: String)(vs: (String, Int)*): Unit = {
map(key) = vs.toMap
}
def selectDynamic(key: String): Map[String, Int] = {
map.getOrElse(key, Map.empty)
}
def applyDynamic(key: String)(s: String): Int = {
selectDynamic(key).getOrElse(s, -1)
}
}
scala> val n = new MyName
n: MyName = MyName@1ffbfdb
scala> n.zzz(aaa = 123, bbb = 456, 789) //applyDynamicNamed
scala> n.zzz //selectDynamic
res39: Map[String,Int] = Map(aaa -> 123, bbb -> 456, "" -> 789)
scala> n.zzz("aaa") //applyDynamic
res40: Int = 123
scala> n.zzz("xyz") //applyDynamic
res41: Int = -1
|
名前付き引数で代入できるようにする例。 |