Table of Contents
Tuples
val stuff = (1,"Hello", true) //un exemple de tuple- une structure de données très simple
- paquet d’un nombre fixe de données manipulées comme un tout
- l’ordre dans lequel on place les données est important
La syntaxe est de séparer les types par des virgules, le tout dans une parenthèse.
(Typ1, Typ2, Typ3, ... TypN)Il est possible de déclarer des val/var contenant des tuples
val foo: (String, Int, Char) = ("Wow", 1, 'z')var zo: (Char, (Int, Double)) = ('a', (42, 3.2))Accéder aux composantes
On utilise la syntaxe ._i
val foo: (String, Int, Int) = ("Wow", 1, 2)println(foo._1) // affiche "Wow" en consoleval sum: Int = foo._2 + foo._3 // sum vaut 1 + 2 = 3val zo: (Char, (Int, Double)) = ('a', (42, 3.2))println(zo._2._1) // affiche 42 en consolePattern-matching
Syntaxe :
expr match { case (... , ... , ...) => ... case (... , ... , ...) => ... ... case (... , ... , ...) => ...}Motifs imbriqués
⇒ Permet de gagner en concision, un seul motif exprime alors plusieurs critères en même temps
/** * UserInfo : un triplet (3-tuple): * identifiant, mot de passe, et droits admin */type UserInfo = (String, String, Boolean)
val user1: UserInfo = ("georges", "9999", false)val user2: UserInfo = ("nlambert", "aeNg9aip", true)/** * @param user un utilisateur * @return le login de user s'il est admin, sinon "Not an admin". */
def unameOfAdmin(user: UserInfo): String = { user match { case (uname, _, true) => uname case _ => "Not an admin" }}Cela permet d’analyser la structure d’une valeur de façon “profonde” en imbriquant les motifs.
Types algébriques
Les tuples :
- utiles pour regrouper plusieurs données en une seule
typealias pour les tuples : améliore la lisibilité
type Data = (Int,Int,Int) //jour, mois, annéeUn alias est juste un autre nom, pas un nouveau type
- Accès aux composantes
._i: sujet à erreur (par exemple date en FR et ENG) ⇒ solution (partielle) → le pattern-matching et les motifs variables - Type sans alternatives : taille fixe ⇒ un -tuple aura toujours composantes
Les types algébriques permettent de
- définir un nouveau type de données, composite
- nommer les composantes du type
- autoriser les alternatives
case class
Par exemple pour modéliser une date par un jour, un mois et une année
Déclaration de type :
case class Date(jour: Int, mois: Int, an: Int)Création de valeurs :
Date(25,12,2018)Pas de mot-clef new, la valeur est uniquement définie par le nom du constructeur et la valeur des composantes
Date est le nom du type et du constructeur
Pour accéder aux composantes, on utilise leur nom (notation pointée) :
val d: Date = Date(10, 11, 2012)println(d.jour + "-" + d.mois + "-" + d.an) // 10-11-2012Les case class sont immutables, on doit donc renvoyer de nouvelles valeurs
/** * @param d une date * @return le début de mois pour la date d */def debutMois(d: Date): Date = { Date(1, d.mois, d.an)}Pour le pattern-matching, Date peut aussi être un motif :
/** * @param d une date * @return une chaîne décrivant la date */def description(d: Date): String = { d match { case Date(25, 12, _) => "Noël" case Date(31, 10, _) => "Halloween" case Date(14, 2, _) => "St Valentin" case _ => "" }}sealed trait et extends
Une image peut être :
- soit un rectangle : défini par sa longueur et sa largeur
- soit un cercle : défini par son rayon
- soit plus compliquée : celle contenue dans un fichier
⇒ Création de type qui réunissent des types créés avec case class
Nommage du nouveau type par sealed trait Type
sealed trait Imagecase class Rectangle(w: Float, h: Float) extends Imagecase class Circle(r: Float) extends Imagecase class FromFile(filename: String) extends ImageOn autorise des alternatives par extends ⇒ ici 3 variantes pour le type Image
Le mot-clé sealed : ces variantes (les case class de ce fichier) sont les seules possibles.
==On peut donc créer des types de tailles diverses et hétérogènes dans leurs types==
On a le choix pour le type déclaré ⇒ cela détermine la validité des accès aux composantes.
val r1: Rectangle = Rectangle(1, 3) // r1 de type Rectangleprintln("Aire de r1 = " + (r1.h * r1.w)) // accès composantes OKval r2: Image = Rectangle(2, 4) // r2 de type Imageprintln("Aire de r2 = " + ???) // r2.h et r2.w n'existent pasLe type de la variante, ici Rectangle, est plus précis. Souvent, en programmation, il vaut mieux, quand c’est possible, réfléchir de manière générale, sur le type algébrique global, ici Image.
Les types algébriques simples sont immutables ⇒ composés de case class
Pattern-matching :
- motifs des constructeurs: traiter tous les cas possibles
- motifs des composantes: accéder à leur contenu
/*** @param i une image* @return i est un cercle de manière certaine* */def estUnCercle(i: Image): Boolean = { i match { case Circle(_) => true case Rectangle(_, _) => false case FromFile(_) => false }}Le type Scala Option[T]
On souhaite calculer l’aire d’une image, on peut pour un cercle, pour un rectangle, mais pas pour un fichier (d’après les case class définis précédemment)
On peut définir un nouveau type algébrique représentant qu’un résultat n’existe pas toujours :
sealed trait Resultcase class Ok(r: Double) extends Resultcase object Undef extends ResultUne case class sans composante se note case object
Puis on peut utiliser ce type pour définir notre fonction :
def aire(i: Image): Result = { i match { case Circle(r) => Ok(math.Pi * r * r) case Rectangle(h, w) => Ok(h * w) case FromFile(_) => Undef }}Un type prédéfini joue le rôle du type Result : le type Option[T] où T est un type quelconque (Double dans l’exemple) avec 2 alternatives :
Some: 1 composante de typeTNone: pas de composante.
/*** @param i une image* @return l'aire de l'image i, si on peut la calculer sans effet* */def aire(i: Image) : Option[Double] = { i match { case Circle(r) => Some(math.Pi * r * r) case Rectangle(h, w) => Some(h * w) case FromFile(_) => None }}Bilan
Types de données composites :
- tuples et types algébriques
- modéliser des données composites, agrégeant plusieurs informations
Pattern-matching :
- motif tuples, variables, imbriqués, et constructeur
- motifs: contraintes sur les valeurs possibles
- moyen d’accéder au contenu effectif des composantes de la valeur composite