web-dev-qa-db-fra.com

Quelle est la fonction apply dans Scala?

Je n’ai jamais compris cela à partir des noms inventés et vérifiant (une classe AddTwo a une apply qui ajoute deux!) Exemples.

Je comprends que c'est un sucre syntaxique, donc (je déduis du contexte) il doit avoir été conçu pour rendre un code plus intuitif.

Quel sens une classe avec une fonction apply donne-t-elle? À quoi est-il utilisé et à quelles fins améliore-t-il le code (suppression du nom, vérification des noms, etc.)?

comment cela aide-t-il lorsqu'il est utilisé dans un objet compagnon?

286
Jesvin Jose

Les mathématiciens ont leurs propres petites manières amusantes, donc au lieu de dire "nous appelons alors fonction f en le passant x en tant que paramètre", comme diraient les programmeurs, ils parlent de "appliquer la fonction f à son argument x ".

En mathématiques et en informatique, Apply est une fonction qui applique des fonctions à des arguments.
Wikipedia

apply a pour but de réduire l'écart entre les paradigmes fonctionnel et orienté objet de Scala. Chaque fonction de Scala peut être représentée sous forme d'objet. Chaque fonction a également un type OO: par exemple, une fonction qui prend un paramètre Int et renvoie un Int aura le type OO Function1[Int,Int].

 // define a function in scala
 (x:Int) => x + 1

 // assign an object representing the function to a variable
 val f = (x:Int) => x + 1

Puisque tout est un objet dans Scala, _ f peut maintenant être traité comme une référence à Function1[Int,Int] objet. Par exemple, nous pouvons appeler la méthode toString héritée de Any, ce qui aurait été impossible pour une fonction pure, car les fonctions n'ont pas de méthodes:

  f.toString

Ou nous pourrions définir un autre objet Function1[Int,Int] en appelant la méthode compose sur f et en chaînant deux fonctions différentes:

 val f2 = f.compose((x:Int) => x - 1)

Maintenant, si nous voulons réellement exécuter la fonction, ou comme le dit un mathématicien "appliquer une fonction à ses arguments", nous appellerions la méthode apply sur l'objet Function1[Int,Int]:

 f2.apply(2)

Écrire f.apply(args) chaque fois que vous souhaitez exécuter une fonction représentée sous la forme d'un objet correspond à la méthode orientée objet, mais ajouterait beaucoup de fouillis au code sans ajouter beaucoup d'informations supplémentaires et il serait agréable de pouvoir l'utiliser. notation plus standard, telle que f(args). C'est là que le compilateur Scala intervient et chaque fois que nous avons une référence f à un objet fonction et écrivez f (args) pour appliquer des arguments à la fonction représentée, le compilateur étend silencieusement f (args) à l'appel de méthode d'objet f.apply (args).

Chaque fonction de Scala peut être traitée comme un objet et fonctionne dans l'autre sens: chaque objet peut être traité comme une fonction, à condition qu'il utilise la méthode apply. De tels objets peuvent être utilisés dans la notation de fonction:

// we will be able to use this object as a function, as well as an object
object Foo {
  var y = 5
  def apply (x: Int) = x + y
}


Foo (1) // using Foo object in function notation 

Il existe de nombreux cas d'utilisation lorsque l'on souhaite traiter un objet comme une fonction. Le scénario le plus courant est un modèle d'usine . Au lieu d'ajouter du fouillis au code en utilisant une méthode de fabrique, nous pouvons apply objecter à un ensemble d'arguments pour créer une nouvelle instance d'une classe associée:

List(1,2,3) // same as List.apply(1,2,3) but less clutter, functional notation

// the way the factory method invocation would have looked
// in other languages with OO notation - needless clutter
List.instanceOf(1,2,3) 

Donc, la méthode apply n'est qu'un moyen pratique de combler le fossé entre les fonctions et les objets dans Scala.

598
Vlad Gudim

Cela vient de l'idée que vous voulez souvent appliquer quelque chose à un objet. L'exemple le plus précis est celui des usines. Quand vous avez une usine, vous voulez appliquer paramètre pour créer un objet.

Les gars de Scala pensaient que, comme cela se produit souvent, il pourrait être agréable d’avoir un raccourci pour appeler apply. Ainsi, lorsque vous donnez des paramètres directement à un objet, il est préférable de passer ces paramètres à la fonction apply de cet objet:

class MyAdder(x: Int) {
  def apply(y: Int) = x + y
}

val adder = new MyAdder(2)
val result = adder(4) // equivalent to x.apply(4)

Il est souvent utilisé dans un objet compagnon, pour fournir une méthode de fabrique Nice pour une classe ou un trait, en voici un exemple:

trait A {
  val x: Int
  def myComplexStrategy: Int
}

object A {
  def apply(x: Int): A = new MyA(x)

  private class MyA(val x: Int) extends A {
    val myComplexStrategy = 42
  }
}

À partir de la bibliothèque standard scala, vous pouvez voir comment scala.collection.Seq est implémenté: Seq est un trait, donc new Seq(1, 2) ne sera pas compilé mais grâce à l'objet compagnon et appliquer, vous pouvez appeler Seq(1, 2) et l'implémentation est choisie par l'objet compagnon.

46
Nicolas

Voici un petit exemple pour ceux qui veulent parcourir rapidement

 object ApplyExample01 extends App {


  class Greeter1(var message: String) {
    println("A greeter-1 is being instantiated with message " + message)


  }

  class Greeter2 {


    def apply(message: String) = {
      println("A greeter-2 is being instantiated with message " + message)
    }
  }

  val g1: Greeter1 = new Greeter1("hello")
  val g2: Greeter2 = new Greeter2()

  g2("world")


} 

sortie

Un greeter-1 est en cours d'instanciation avec le message hello

Un greeter-2 est en cours d'instanciation avec le monde des messages

7
sdinesh94