サーチ…


前書き

Scalaでは、メソッドを呼び出したり、オブジェクトのフィールドにアクセスしたりするときに、動的呼び出しを使用することができます。これを言語に深く組み込むのではなく、マーカー特性[ scala.Dynamic ] [Dynamic scaladoc]によって有効にされる暗黙的な変換と同様のルールを書き直すことで実現します。これにより、動的言語などに存在するオブジェクトにプロパティを動的に追加する機能をエミュレートできます。 [dynamic scaladoc]:http://www.scala-lang.org/api/2.12.x/​​scala/Dynamic.html

構文

  • Fooクラスは動的に拡張されています
  • foo.field
  • foo.field = value
  • foo.method(args)
  • foo.method(名前付きArg = x、y)

備考

Dynamicサブタイプを宣言するには、 -language:dynamicsインポートscala.language.dynamicsか、 -language:dynamicsコンパイラオプションを使用して、言語機能のdynamics有効にする必要があります。このDynamicユーザーは、独自のサブタイプを定義していないため、これを有効にする必要はありません。

フィールドアクセス

この:

class Foo extends Dynamic {
  // Expressions are only rewritten to use Dynamic if they are not already valid
  // Therefore foo.realField will not use select/updateDynamic
  var realField: Int = 5
  // Called for expressions of the type foo.field
  def selectDynamic(fieldName: String) = ???
  def updateDynamic(fieldName: String)(value: Int) = ???
}

フィールドへの簡単なアクセスを可能にします:

val foo: Foo = ???
foo.realField // Does NOT use Dynamic; accesses the actual field
foo.realField = 10 // Actual field access here too
foo.unrealField // Becomes foo.selectDynamic(unrealField)
foo.field = 10  // Becomes foo.updateDynamic("field")(10)
foo.field = "10" // Does not compile; "10" is not an Int.
foo.x() // Does not compile; Foo does not define applyDynamic, which is used for methods.
foo.x.apply() // DOES compile, as Nothing is a subtype of () => Any
// Remember, the compiler is still doing static type checks, it just has one more way to
// "recover" and rewrite otherwise invalid code now.

メソッド呼び出し

この:

class Villain(val minions: Map[String, Minion]) extends Dynamic {
  def applyDynamic(name: String)(jobs: Task*) = jobs.foreach(minions(name).do)
  def applyDynamicNamed(name: String)(jobs: (String, Task)*) = jobs.foreach {
    // If a parameter does not have a name, and is simply given, the name passed as ""
    case ("", task) => minions(name).do(task)
    case (subsys, task) => minions(name).subsystems(subsys).do(task)
  }
}

名前付きパラメータの有無にかかわらず、メソッドへの呼び出しを許可します。

val gru: Villain = ???
gru.blu() // Becomes gru.applyDynamic("blu")()
// Becomes gru.applyDynamicNamed("stu")(("fooer", ???), ("boomer", ???), ("", ???),
//         ("computer breaker", ???), ("fooer", ???))
// Note how the `???` without a name is given the name ""
// Note how both occurrences of `fooer` are passed to the method
gru.stu(fooer = ???, boomer = ???, ???, `computer breaker` = ???, fooer = ???)
gru.ERR("a") // Somehow, scalac thinks "a" is not a Task, though it clearly is (it isn't)

フィールドアクセスと更新メソッドとの相互作用

やや反抗的に(だけでなく、それを動作させるための賢い方法)、これは:

val dyn: Dynamic = ???
dyn.x(y) = z

次のものと同等です。

dyn.selectDynamic("x").update(y, z)

while

dyn.x(y)

まだです

dyn.applyDynamic("x")(y)

これを知っておくことが重要です。そうでない場合は、気付かれずに息を引き出して、奇妙なエラーを引き起こす可能性があります。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow