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 |
名前付き引数で代入できるようにする例。 |