c`est simple pour les développeurs Java Pascal Wassong

publicité
c'est simple
pour les développeurs Java
Pascal Wassong
Une classe Scala
package com.example.scala
import scala.annotation.tailrec
class Rationel(num: Int, denom: Int) {
def this(n: Int) = this(n, 1)
private val p = pgcd(num, denom)
val numerateur = num / p
val denominateur = denom / p
lazy val reel = numerateur.toFloat / denominateur
println("valeur réelle = " + reel)
override def toString =
numerateur.toString + " / " + denominateur.toString
@tailrec
private def pgcd(a: Int, b: Int): Int =
if (b == 0) a else pgcd(b, a % b)
}
Moins de limitations qu'en Java
●
Scala a un « interpréteur » (REPL)
la commande : scala
●
●
Pas de limite au nombre de classes par fichier
Une classe peut être définie à l'intérieur d'une
autre
●
Package comme en Java
●
Pas de contraintes sur l'emplacement d'un fichier
Une classe
●
Déclarer une classe
class Rationel(num: Int, denom: Int) { … }
●
Constructeur primaire et secondaire
●
« extends » une seule autre classe
●
Utilisation de traits avec le mot clé « with »
class MaClasse extends AutreClasse with TraitA with TraitB { … }
●
Classe abstraite comme en Java : abstract
Import
●
Importer une classe comme en Java
●
La clause import peut être utilisée n'importe où
●
Importer toutes les classes d'un package
import java.util._
●
Importer plusieurs classes d'un package
import java.util.{LinkedList, HashMap}
●
Renommer une classe importée
import java.util.Date
import java.sql.{Date => SqlDate}
class MaClasse {
val date: Date = new Date()
val sqlDate: SqlDate = new SqlDate(date.getTime())
}
Une classe Scala
package com.example.scala
import scala.annotation.tailrec
class Rationel(num: Int, denom: Int) {
def this(n: Int) = this(n, 1)
private val p = pgcd(num, denom)
val numerateur = num / p
val denominateur = denom / p
lazy val reel = numerateur.toFloat / denominateur
println("valeur réelle = " + reel)
override def toString =
numerateur.toString + " / " + denominateur.toString
@tailrec
private def pgcd(a: Int, b: Int): Int =
if (b == 0) a else pgcd(b, a % b)
}
Un trait
trait Compteur {
def maxAutorise: Int
var compteur = 0
def incremente(): Unit = compteur += 1
}
●
Un trait est comme une interface Java, en mieux.
●
Peut définir des méthodes, des var et des val.
●
Peut contenir du code, et donner des valeurs aux val et
var.
●
Pas de constructeur, donc pas d'arguments.
●
Peux étendre un autre trait avec extends.
Quelques mots réservés
●
var, def
●
val : équivalent de l'ajout de « final » en Java
●
●
●
private, protected, public est par défaut. Le
mot clé n'existe pas.
override est un mot clé
lazy val : la valeur n'est initialisée qu'au 1 er
accès
Inférence de type
●
●
Souvent, le compilateur a les moyens de trouver le
type d'une expression
Par exemple
val i = 1
<=>
val s = "une chaîne"
val i: Int = 1
<=>
val s: String = "une chaîne"
def pair(n: Int) = if (n % 2 == 0) "pair" else "impair"
def pair(n: Int): String = if (n % 2 == 0) "pair" else "impair"
●
●
Conseillé pour le type de retour de toutes les
méthodes
Obligatoire pour les méthodes récursives
Une classe Scala
package com.example.scala
import scala.annotation.tailrec
class Rationel(num: Int, denom: Int) {
def this(n: Int) = this(n, 1)
private val p = pgcd(num, denom)
val numerateur = num / p
val denominateur = denom / p
lazy val reel = numerateur.toFloat / denominateur
println("valeur réelle = " + reel)
override def toString =
numerateur.toString + " / " + denominateur.toString
@tailrec
private def pgcd(a: Int, b: Int): Int =
if (b == 0) a else pgcd(b, a % b)
}
Les choses optionnelles
override def toString = numerateur.toString + " / " + denominateur.toString
override def toString(): String = {
return numerateur.toString() + " / " + denominateur.toSring();
}
●
;
●
() : si pas d'argument => transparence référentielle
●
{} : si une seule expression
●
Le type de retour : trouvé par inférence
●
return : tout est expression
object
object Rationel {
def apply(n: Int, d: Int) = new Rationel(n, d)
def apply(n: Int) = new Rationel(n, 1)
val UN = Rationel(1)
}
●
Singleton
●
Méthodes « static »
●
Objet compagnon
●
La méthode magique « apply »
Tout est objet, tout est expression
●
Tout est objet, les méthodes aussi
2.to(10) ou bien "314".toInt
def double(i: Int): Int = i * 2
def calculer(i: Int, fct: (Int) => Int): Int = fct(i) + i
calculer(3, double) + calculer(3, i => i * i)
●
Tout est une expression
val s = "314"
val i = try {
s.toInt
} catch {
case e: java.lang.NumberFormatException => 0
}
val res = if (i % 2 == 0) i / 2 else 3 * i + 1
●
Unit est l'équivalent de « void » en Java
Domain Specific Language
●
●
●
Dans l'appel d'une fonction, le point « . » est optionnel.
Une fonction avec un seul argument peut être
invoquée sans écrire les parenthèses
Deux exemples
2.to(10) <=> 2 to 10
2 + i
●
<=> 2.+(i)
Surcharge des opérateurs (ne pas abuser)
–
Tous les caractères peuvent être utilisés dans les noms des
méthodes. Par exemple : def \:/ = "victoire"
Exemple de DSL : ScalaTest
import collection.mutable.Stack
import org.scalatest._
class ExampleSpec extends FlatSpec with Matchers {
"A Stack" should "pop values in last­in­first­out order" in {
val stack = new Stack[Int]
stack.push(1)
stack.push(2)
stack.pop() should be (2)
stack.pop() should be (1)
}
it should "throw NoSuchElementException if an empty stack is popped" in {
val emptyStack = new Stack[Int]
a [NoSuchElementException] should be thrownBy {
emptyStack.pop()
} }
}
Tuple (n-uplet)
●
Un tuple permet de rassembler plusieurs valeurs
def bornes(liste: List[Int]): (Int, Int) = {
val min = liste.min
val max = liste.max
(min, max)
}
val liste = List(2, 3, 5, 7, 11, 13)
val minMax = bornes(liste)
println( s"min = ${minMax._1}, max = ${minMax._2}" )
●
Mieux
val (min, max) = bornes(liste)
println( s"min = $min, max = $max" )
●
Et encore mieux …
case class
case class Bornes(min: Int, max: Int)
val b = Bornes(2, 13)
println(b.toString)
●
Création d'une classe complète en une seule
ligne
●
Ce sont des val par défaut
●
Accès aux valeurs
●
toString, equals, hashCode
●
Objet compagnon avec la fabrique apply
Pattern matching
def texte(liste: List[Int]): String = liste match {
case Nil => "La liste est vide"
case List(x) => "La liste contient un seul element : " + x
case x :: xs if x == 0 => "La liste commence par 0"
case _ => "Tous les autres cas"
}
●
Mille fois plus puissant qu'un switch
●
Déconstruction : les variables x et xs contiennent les valeurs
●
if est une clause de garde
●
:: est l'opérateur définit sur List pour ajouter un élément en
tête de liste
Les boucles
●
while
var i = 0
while (i < 10) {
println(s"i = $i")
i = i + 1
}
●
for
for (i <­ 0 to 9) println(s"i = $i")
●
foreach
(0 to 9).foreach(i => println(i))
val liste = List(2, 3, 5, 7, 11, 13)
liste.foreach(n => println(n))
●
zipWithIndex
liste.zipWithIndex.foreach { case (n, i) => println(s"$i: $n") }
Programmation fonctionnelle
●
Un exemple
val liste = List(2, 3, 5, 7, 11, 13)
liste.filter(_ > 10).map(_ * 2).foreach(println)
●
●
Les collections sont immutables par défaut.
Le type Option[T], pour éviter l'utilisation de
null.
L’écosystème Scala
●
●
Livre : « Programming in Scala » de Odersky, Spoon et
Venners : http://www.artima.com/pins1ed
Scaladoc :
http://www.scala-lang.org/api/current/index.html
●
Librairie akka (acteur) avec interface Java
●
Frameworks Web en Scala : Play, spray, Lift
●
IDE : plugins pour IntelliJ et Eclipse (ensime pour emacs)
●
Utilisateurs de Scala : Twitter, LinkedIn, TheGuardian, etc …
●
Introduction de Scala dans les tests unitaires
Merci pour votre attention
[email protected]
Ce document est Copyright © Pascal Wassong 2016, Creative Commons : CC-BY-ND-SA
L'image page 2 est © Tomi Ungerer
Téléchargement