Scala Language
Les fonctions
Recherche…
Remarques
Scala a des fonctions de première classe.
Différence entre les fonctions et les méthodes:
Une fonction n'est pas une méthode dans Scala: les fonctions sont une valeur et peuvent être affectées en tant que telles. Les méthodes (créées avec def
), en revanche, doivent appartenir à une classe, à un trait ou à un objet.
- Les fonctions sont compilées dans une classe étendant un trait (tel que
Function1
) au moment de la compilation et sont instanciées à une valeur lors de l'exécution. Les méthodes, quant à elles, sont membres de leur classe, trait ou objet et n'existent pas en dehors de cela. - Une méthode peut être convertie en une fonction, mais une fonction ne peut pas être convertie en une méthode.
- Les méthodes peuvent avoir un paramétrage de type, contrairement aux fonctions.
- Les méthodes peuvent avoir des valeurs par défaut, alors que les fonctions ne le peuvent pas.
Fonctions anonymes
Les fonctions anonymes sont des fonctions définies mais sans nom.
Voici une fonction anonyme qui prend deux entiers et renvoie la somme.
(x: Int, y: Int) => x + y
L'expression résultante peut être affectée à un val
:
val sum = (x: Int, y: Int) => x + y
Les fonctions anonymes sont principalement utilisées comme arguments pour d'autres fonctions. Par exemple, la fonction map
sur une collection attend une autre fonction comme argument:
// Returns Seq("FOO", "BAR", "QUX")
Seq("Foo", "Bar", "Qux").map((x: String) => x.toUpperCase)
Les types des arguments de la fonction anonyme peuvent être omis: les types sont inférés automatiquement :
Seq("Foo", "Bar", "Qux").map((x) => x.toUpperCase)
S'il n'y a qu'un seul argument, les parenthèses autour de cet argument peuvent être omises:
Seq("Foo", "Bar", "Qux").map(x => x.toUpperCase)
Raccourci sténographie
Il existe une syntaxe encore plus courte qui ne nécessite pas de noms pour les arguments. L'extrait ci-dessus peut être écrit:
Seq("Foo", "Bar", "Qux").map(_.toUpperCase)
_
représente les arguments de la fonction anonyme en position. Avec une fonction anonyme dotée de plusieurs paramètres, chaque occurrence de _
fera référence à un argument différent. Par exemple, les deux expressions suivantes sont équivalentes:
// Returns "FooBarQux" in both cases
Seq("Foo", "Bar", "Qux").reduce((s1, s2) => s1 + s2)
Seq("Foo", "Bar", "Qux").reduce(_ + _)
Lors de l'utilisation de cet raccourci, tout argument représenté par la position _
ne peut être référencé qu'une seule fois et dans le même ordre.
Fonctions anonymes sans paramètres
Pour créer une valeur pour une fonction anonyme ne prenant pas de paramètres, laissez la liste de paramètres vide:
val sayHello = () => println("hello")
Composition
La composition des fonctions permet à deux fonctions de fonctionner et d'être considérées comme une fonction unique. Exprimée en termes mathématiques, étant donné une fonction f(x)
et une fonction g(x)
, la fonction h(x) = f(g(x))
.
Lorsqu'une fonction est compilée, elle est compilée dans un type lié à Function1
. Scala propose deux méthodes dans la Function1
mise en œuvre liées à la composition: andThen
et compose
. La méthode de compose
correspond à la définition mathématique ci-dessus comme suit:
val f: B => C = ...
val g: A => B = ...
val h: A => C = f compose g
The andThen
(pensez que h(x) = g(f(x))
) a un sentiment plus "DSL-like":
val f: A => B = ...
val g: B => C = ...
val h: A => C = f andThen g
Une nouvelle fonction anonyme est allouée avec celle qui est fermée sur f
et g
. Cette fonction est liée à la nouvelle fonction h
dans les deux cas.
def andThen(g: B => C): A => C = new (A => C){
def apply(x: A) = g(self(x))
}
Si f
ou g
fonctionne via un effet secondaire, alors l'appel de h
provoquera tous les effets secondaires de f
et g
dans l'ordre. La même chose est vraie de tout changement d'état mutable.
Relation avec les fonctions partielles
trait PartialFunction[-A, +B] extends (A => B)
Chaque PartialFunction
un seul argument est également une Function1
. Ceci est contre-intuitif dans un sens mathématique formel, mais correspond mieux au design orienté objet. Pour cette raison, il n'est pas nécessaire que Function1
fournisse une méthode isDefinedAt
true
isDefinedAt
.
Pour définir une fonction partielle (qui est aussi une fonction), utilisez la syntaxe suivante:
{ case i: Int => i + 1 } // or equivalently { case i: Int ⇒ i + 1 }
Pour plus de détails, consultez les fonctions partielles .