2 votes

Scala, passer une fonction définie localement dans une liste ?

Je n'ai pas compris pourquoi l'extrait de code suivant afterDelay(0) {...} une fonction définie localement peut être stockée dans l'agenda ? Quelqu'un peut-il m'aider à comprendre le afterDelay(0) {...} dans le run fonction ?

abstract class Simulation {

  type Action = () => Unit

  case class WorkItem(time: Int, action: Action)

  private var curtime = 0
  def currentTime: Int = curtime

  private var agenda: List[WorkItem] = List()

  private def insert(ag: List[WorkItem], item: WorkItem): List[WorkItem] = {
    if (ag.isEmpty || item.time < ag.head.time) item :: ag
    else ag.head :: insert(ag.tail, item)
  }

  def afterDelay(delay: Int)(block: => Unit) {
    val item = WorkItem(currentTime + delay, () => block)
    agenda = insert(agenda, item)
  }

  private def next() {
    (agenda: @unchecked) match {
      case item :: rest => 
        agenda = rest 
        curtime = item.time
        item.action()
    }
  }

  def run() {
    afterDelay(0) {
      println("*** simulation started, time = "+
          currentTime +" ***")
    }
    while (!agenda.isEmpty) next()
  }
}

3voto

afterDelay(0) {
    println(...)
}

Est équivalent à ce qui suit :

afterDelay(0)({
    println(...)
})

La fonction afterDelay est invoqué, un nouveau WorkItem ( item ) est ajouté à la liste, et non la fonction elle-même. Le paramètre block: => Unit est un "paramètre de nom". (voir le Spécification du langage Scala section 4.6.1) : l'expression utilisée comme argument est implicitement convertie en une "méthode sans paramètre" ( sans qui est évaluée en premier) qui sera invoquée à chaque fois que la variable contenue dans la méthode est accédée (pas d'appel à la méthode). () nécessaire).

Dans ce cas, c'est lorsque la fonction résultant de () => block est invoqué : il est invoqué à item.action() qui se produit à un moment donné après le nouveau WorkItem est ajouté à la liste (et afterDelay retours).

S'il était écrit comme (en prenant un paramètre de fonction, pas un by-name/thunk) :

def afterDelay(delay: Int)(block: () => Unit) {   // take a function
  // new function will invoke function named by "block" when invoked ...
  val item = WorkItem(..., () => block())
  // or skip wrapping the function in a function ...
  // val item = WorkItem(..., block)
  ...
}

Il faudrait alors l'invoquer en passant dans un fichier fonction :

afterDelay(0)(() => { // need a function
    println(...)
})

Ou encore, une syntaxe alternative, toujours en fonction de () => Unit mais la parenthèse extérieure peut être évitée :

afterDelay(0) { () => // need a function
    println(...)
} 

Extrait du SLS, 4.6.1 By-Name Parameters :

Le type d'un paramètre de valeur peut être prefixé par le texte suivant => par exemple x: => T . Le type d'un tel paramètre est alors le type de méthode sans paramètre => T . Cela indique que l'argument correspondant est pas évaluée au point d'application de la fonction, mais est plutôt évaluée à chaque utilisation dans le cadre de la fonction . C'est-à-dire que l'argument est évalué en utilisant l'appel par nom.

1voto

T.Grottker Points 1301

Vous avez défini afterDelay comme un fonction curry . Cela signifie qu'il a deux listes de paramètres. En scala, vous pouvez remplacer les parenthèses entourant la liste de paramètres par les termes suivants (...) avec {...} . Dans la deuxième liste de paramètres, vous utilisez un paramètre "call-by-name" (appel par nom) . Ces paramètres sont évalués chaque fois que vous les utilisez dans votre fonction. Un bon exemple est aquí .
Les paramètres "Call-by-name" sont souvent utilisés pour définir votre propre structure de contrôle.

def do(until: Int)(body: => Unit) {
  body
  if (until > 1) do(until - 1)(body)
}

do(0)(println("test"))
do(5)(println("test2"))

Il s'agit d'un exemple de "faire jusqu'à". Il s'imprimera une fois test et cinq fois test2 .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X