Scala Language
Динамический вызов
Поиск…
Вступление
Scala позволяет использовать динамический вызов при вызове методов или доступе к полям на объекте. Вместо того, чтобы встроить этот язык глубоко в язык, это достигается путем переписывания правил, аналогичных правилам неявных преобразований, которые активируются маркерным признаком [
scala.Dynamic
] [Dynamic scaladoc]. Это позволяет эмулировать способность динамически добавлять свойства к объектам, присутствующим в динамических языках, и многое другое. [Dynamic scaladoc]: http://www.scala-lang.org/api/2.12.x/scala/Dynamic.html
Синтаксис
- класс Foo расширяет динамический
- foo.field
- foo.field = значение
- foo.method (арг)
- foo.method (namedArg = x, y)
замечания
Чтобы объявить подтипы Dynamic
, dynamics
характеристик языка необходимо активировать, импортируя scala.language.dynamics
или -language:dynamics
compiler. Пользователи этого 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)
в то время как
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