La précédence désigne la priorité et la force des différents opérateurs.
En mathématique les différents opérateurs ont des priorités différentes, par exemple la multiplication prend le pas sur l’addition.
De fait en ruby, comme dans bien d’autres langages, cette expression retourne le résultat attendu :
2 + 3 * 4
=> 14
Pour reprendre la main sur le flux des opérateurs on peut bien sûr utiliser des parenthèses :
(2 + 3) * 4
=> 20
Les opérateurs sont les suivants, de la précédence la plus élevée à la plus faible :
[] et []= | Accès à un élément du tableau et set d'une valeur |
** | Exponentiel |
! ~ + - | Inversion, complément (remplace les bits 0 par 1 et vice-versa), plus et moins (-2 ou +3) |
* / % | Multiplication, division et modulo |
+ - | Addition et soustraction |
<< >> | Décallage de bit vers la droite ou gauche. Retire des bits à droite, ajoute des 0 à gauche. Ex: (9 >> 1).to_s(2) |
& | AND, opérateur bit à bit, 1 si 1 des deux côtés, 0 sinon. (9 & 14).to_s(2) donne en binaire 1001 & 1110 = 1000 (8) |
^ | | ^ est l'opérateur bit à bit XOR (ou exclusif). 1 si uniquement un des deux bits est à 1. | est l'opérateur bit à bit OR. 1 si 1 d'un côté au moins. |
<= < > >= | Opérateurs de comparaison |
<=> == === != =~ !~ | Comparaison d'égalité ou de matching |
&& | Et logique. Vrai si les des deux éléments sont évalués à vrai. `true && false` renvoie false. |
|| | Ou logique. Vrai si l'un des deux éléments est évalué à vrai. `true || false` renvoie true. |
.. ... | Range incluant et excluant la borne haute : Ex `(1..3).to_a == [1, 2, 3]`. `(1...3).to_a == [1, 2]` |
? : | Ternaire. Ex: `i % 2 == 0 ? "even" : "odd"` |
= += -= &&= etc… | Affectations |
defined? | Vérifie la définition ou non d'une variable |
not | Négation logique |
or and | Composition logique |
if unless while until | Conditions et boucles |
begin end | Blocs |
La précédence des opérateurs peut avoir des conséquences importantes pour des opérateurs qui semblent avoir le même usage.
C’est le cas de &&
et and
tout comme ||
et or
.
Prenons l’exemple suivant :
a = []
b = 1
c = a.empty? and b.is_a?(String)
Le dernier retour sera ici false
et c
sera true
ce qui peut paraître suprenant.
On le comprend mieux en prennant en compte la précédence. L’interpréteur ruby va «lire» l’expression de la sorte :
a = []
b = 1
(c = a.empty?) and b.is_a?(String)
En effet l’affectation a une précédence plus forte que le and
comme on l’a vu dans le tableau ci dessus.
Avec le &&
logique le résultat est tout autre et plus proche de ce que l’on attend naturellement :
a = []
b = 1
c = a.empty? && b.is_a?(String)
Le retour est false
et c
également car l’expression se décompose de la sorte :
a = []
b = 1
c = (a.empty? && b.is_a?(String))
Il en est de même pour les opérateurs or
et ||
. Il faut en fait voir les opérateurs or
et and
comme des opérateurs de gestion de flux.
Leur usage est donc plus proche de celui de conditions telles que if
, else
ou unless
que d’un opérateur logique.
Vous avez sans doute déjà vu en Perl ou en PHP des instructions telles que :
chdir '/foo/bar' or die "Can't cd to bar"
Le fonctionnement est le même en ruby et nous permet de gérer le flux de la sorte :
File.exists?('/tmp/bar') or File.new('/tmp/bar', 'w') {}
ce qui est comparable à :
File.new('/tmp/bar', 'w') {} unless File.exists?('/tmp/bar')
La connaissance des opérateurs et de leur précédence est un aspect important du langage. N’hésitez pas à partager vos retours d’expériences et pièges dans lesquels vous avez pu tomber.
L’équipe Synbioz.
Libres d’être ensemble.