Sök…


Introduktion

Med Scala kan du använda dynamisk kallelse när du ringer till metoder eller når fält på ett objekt. Istället för att ha detta inbyggt djupt i språket åstadkommes detta genom att skriva om regler som liknar de för implicita omvandlingar, aktiverade av markörens drag [ scala.Dynamic ] [Dynamic scaladoc]. Detta gör att du kan emulera möjligheten att dynamiskt lägga till egenskaper till objekt som finns på dynamiska språk och mer. [Dynamisk scaladoc]: http://www.scala-lang.org/api/2.12.x/scala/Dynamic.html

Syntax

  • klass Foo utökar Dynamic
  • foo.field
  • foo.field = värde
  • foo.method (args)
  • foo.method (benämndArg = x, y)

Anmärkningar

För att förklara subtyper av Dynamic , språket har dynamics måste aktiveras, antingen genom att importera scala.language.dynamics eller av -language:dynamics kompilatoralternativet. Användare av denna Dynamic som inte definierar sina egna undertyper behöver inte aktivera detta.

Fältåtkomst

Detta:

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) = ???
}

möjliggör enkel åtkomst till fält:

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.

Metod Samtal

Detta:

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)
  }
}

möjliggör samtal till metoder, med och utan namngivna parametrar:

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)

Interaktion mellan fältåtkomst och uppdateringsmetod

Lite mot intuitivt (men också det enda sunda sättet att få det att fungera), detta:

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

är ekvivalent med:

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

medan

dyn.x(y)

är fortfarande

dyn.applyDynamic("x")(y)

Det är viktigt att vara medveten om detta, annars kan det smyga av obemärkt och orsaka konstiga fel.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow