Cours
Envie d’en savoir plus sur Scala ? Suivez le cours Introduction to Scala de DataCamp.
Scala est un langage de programmation fonctionnel qui traite à la fois les fonctions comme des valeurs de premier ordre et les méthodes, avec des similarités et des différences entre les deux. Fonctions et méthodes sont des blocs de code réutilisables, utiles pour centraliser du code répétitif et l’appeler pour accomplir une tâche précise. Elles facilitent aussi le débogage et la maintenance.
Cela dit, une fonction est un objet que l’on peut affecter à une variable, tandis qu’une méthode commence par le mot-clé 'def' suivi du nom, de la liste de paramètres et du corps qui peut retourner une valeur.
Déclaration et définition d’une méthode
La syntaxe de déclaration et de définition d’une méthode en Scala est la suivante :
def 'method_name' ('parameters':'return_type_parameters') : ('return_type_of_method') = {
'method_body'
return 'value'
}
Une méthode en Scala se compose des éléments suivants :
- 'def' : mot-clé utilisé pour déclarer des méthodes.
- 'method_name' : nom de la méthode, en lower camel case.
- 'parameters' : paramètres de la méthode. Il peut n’y en avoir aucun, un seul, ou plusieurs séparés par des virgules.
- 'return_type_of_parameters' : doit correspondre au type des éléments de 'parameters_list' et est obligatoire.
- 'return_type_of_method' : optionnel. Par défaut, 'Unit' est retourné, mais une valeur peut être renvoyée avec le mot-clé 'return'.
- Symbole d’affectation ('=') : optionnel. S’il est utilisé, il affecte la valeur de retour ; sans lui, la méthode ne retourne rien.
- 'method_body' : bloc de code entre accolades '{}' contenant la logique ou les opérations à effectuer.
- return : mot-clé qui renvoie la valeur souhaitée et termine l’exécution, mais il est rarement utilisé en Scala.
Appel de méthode
La syntaxe d’un appel de méthode en Scala est la suivante :
method_name(arguments)
L’appel se fait simplement avec 'method_name', le nom de la méthode à invoquer, en lui passant les arguments.
Méthode avec arguments nommés
Les arguments nommés permettent d’associer explicitement chaque argument au paramètre correspondant lors de l’appel, en les faisant correspondre un à un. Voici un exemple avec la déclaration, la définition et l’appel de méthode :
object calculateResult {
def funSub(x:Int, y:Int) : Int =
{
var diff:Int = 0
diff = x - y
// return value
return diff
}
def main(args: Array[String]) {
// Function call
println("Difference of the value is: " + funSub(8,6));
println("Difference of the value is " + funSub(y=6,x=8));
}
}
Le programme ci-dessus produit :
Difference of the value is: 2
Difference of the value is: 2
Ce programme définit un objet 'calculateResult' contenant une méthode 'funSub' dont les paramètres x et y sont de type 'Int' et dont le type de retour global est 'Int'. Une instruction d’affectation suit pour attribuer la valeur de retour. Les accolades délimitent le corps de la méthode, dans lequel la variable 'diff' est initialisée à 0. L’appel 'funSub(8,6)' depuis la méthode main associe 8 à 'x' et 6 à 'y', effectue la soustraction, retourne 'diff' et l’affiche. De même, l’appel 'funSub(x=8,y=6)' associe 8 à 'x' et 6 à 'y' indépendamment de l’ordre, réalise la même opération et affiche le résultat.
Valeurs par défaut des paramètres
Vous pouvez définir des valeurs par défaut pour les paramètres d’une méthode en les initialisant, puis appeler la méthode sans passer d’arguments.
object calculateResult {
def funSub(x:Int=9, y:Int=6) : Int =
{
var diff:Int = 0
diff = x - y
// return value
return diff
}
def main(args: Array[String]) {
// Function call
print( "The final value is: " + funSub() );
}
}
Le programme ci-dessus produit :
The final value is: 3
Ici, l’objet 'calculateResult' contient la méthode 'funSub' avec des paramètres x et y de type 'Int', un type de retour 'Int' et une affectation de la valeur de retour. Les accolades marquent le début du corps de méthode, où 'diff' est initialisé à 0. Dans main, l’appel 'funSub()' utilise les valeurs par défaut x = 9 et y = 6, effectue l’opération, retourne 'diff' et l’affiche.
Arguments de longueur variable
Les arguments de longueur variable acceptent un nombre quelconque d’arguments fournis par l’utilisateur. Le dernier paramètre de la méthode est déclaré avec '*' pour indiquer qu’il peut être répété.
object variableArgument {
def main(args: Array[String]) {
printAll("Scala", "is", "great")
}
def printAll(strings: String*) {
var i : Int = 0;
for( value <- strings ){
println(value);
i = i + 1;
}
}
}
Le programme ci-dessus produit :
Scala
is
great
On voit ici un objet 'variableArgument' avec une méthode 'printAll' qui définit un argument de longueur variable 'String*' en fin de liste. À l’appel, on peut passer une liste de chaînes. Cette liste est itérée et chaque élément est affiché depuis la fonction principale.
Fonction récursive
La récursion est une technique de programmation fonctionnelle où l’on résout un problème en le décomposant en sous-problèmes plus petits, similaires au problème initial. On résout ces sous-problèmes puis on combine leurs solutions pour obtenir la solution globale. C’est l’approche « diviser pour régner », qui conduit à un code clair et élégant. Lors de l’écriture d’une fonction récursive, deux points sont essentiels :
- Cas de base : il peut y en avoir plusieurs. Ils doivent être correctement identifiés, sinon la récursion peut devenir infinie. Un cas de base doit avoir une solution immédiate, sans appel récursif.
- Cas récursif : la partie où l’on effectue l’appel récursif. L’idée clé est que, à chaque appel, la taille du problème diminue : on le divise en sous-problèmes jusqu’à atteindre le cas de base. Enfin, on combine les résultats pour résoudre le problème initial.
La factorielle d’un nombre donné est n ! Elle s’exprime mathématiquement ainsi :
On peut noter (n-1).(n-2)...3.2.1 sous la forme (n-1) ! Ainsi, la factorielle d’un nombre n est toujours n × (n-1) !
Voici une résolution récursive du problème :
object factorialDemo {
def main(args: Array[String]) {
for (i <- 1 to 5)
println( "Factorial of " + i + ": = " + factorial(i) )
}
def factorial(n: Int): Int = {
if (n <= 1)
return 1
else
return n * factorial(n - 1)
}
}
Le programme ci-dessus produit :
Factorial of 1: = 1
Factorial of 2: = 2
Factorial of 3: = 6
Factorial of 4: = 24
Factorial of 5: = 120
On définit un objet 'factorialDemo' avec une fonction 'main' qui boucle cinq fois et appelle 'factorial'. La fonction récursive s’appelle elle-même jusqu’au cas de base où n ≤ 1, puis le résultat est renvoyé et affiché.
Fonction anonyme
Une fonction anonyme est une définition légère de fonction sans nom, appelée fonction littérale en Scala.
Syntaxe et exemples de fonctions anonymes :
- Première syntaxe et exemple :
Syntaxe :
('first_variable':'data_type', 'second_variable':'data_type') => "certain_expression"
Exemple :
(var1:String:var2:String) => var1 + var2
OU
- Deuxième syntaxe et exemple :
Syntaxe :
(_:'data_type')operator(_'data_type')
Exemple :
(_:String)+(_:String)
Dans la première forme, l’expression après "=>" est évaluée pour produire une valeur, tandis que la liste des variables avant "=>" sert à l’évaluer.
La seconde forme fonctionne comme un raccourci avec des « jokers » : elle accepte chaque valeur une seule fois, puis applique l’opérateur entre elles.
Voici un exemple de fonction anonyme :
object anonymousDemo
{
def main(args: Array[String])
{
var function1 = (var1:Int, var2:Int) => var1 + var2
var function2 = (_:Int) + (_:Int)
// function call
println(function1(5, 5))
println(function2(7, 3))
}
}
Initializing Scala interpreter ...
Spark Web UI available at http://DESKTOP-03TH7J0:4040
SparkContext available as 'sc' (version = 2.4.3, master = local[*], app id = local-1566986265958)
SparkSession available as 'spark'
<console>:10: error: unbound placeholder parameter
var function2 = {_:Int} + {_:Int}
^
<console>:10: error: unbound placeholder parameter
var function2 = {_:Int} + {_:Int}
^
Le programme ci-dessus produit :
10
10
On voit l’objet 'anonymousDemo' avec une fonction 'main' contenant deux fonctions anonymes. Leur syntaxe diffère mais elles donnent le même résultat. 'function1' reçoit ses paramètres lors de l’appel (ici 5 et 5) et affiche 10 ; 'function2' est appelée avec 7 et 3, accepte des 'Integer' valides, effectue l’addition et affiche le résultat.
Conclusion
Félicitations, vous avez terminé ce tutoriel.
Scala propose de nombreux sujets avancés : fonctions d’ordre supérieur, fonctions imbriquées, curryfication, etc.
Références :
TOUR OF SCALA BASICS
Scala | Functions – Basics
Scala - Functions
Anonymous Functions in Scala
Découvrez aussi le cours Introduction to Scala de DataCamp.