Come ogni linguaggio di programmazione, anche Rust offre molti operatori per il trattamento dei dati. Li illustriamo in questa lezione per poter raggiungere, dopo aver visto variabili e tipi di dato, la completa operatività.
Affrontiamoli suddivisi per categorie.
Operatori aritmetici
Gli operatori aritmetici servono a svolgere operazioni tra numeri e sono:
- + per l'addizione;
- - per la sottrazione;
- * per la moltiplicazione;
- / per il quoziente della divisione;
- % per il resto della divisione.
Ecco un esempio:
fn main() {
// impostiamo il prezzo di un prodotto
let prezzo = 1000.0;
// scegliamo un'aliquota di sconto da applicare
let sconto = 17.5;
// calcoliamo il prezzo scontato
let prezzo_scontato = prezzo*(100.0-sconto)/100.0;
// stampiamo il risultato
println!("Il prodotto scontato del {}% è {} euro",sconto, prezzo_scontato);
}
L'esecuzione stampa il messaggio Il prodotto scontato del 17.5% è 825 euro
. Ricordiamo che i numeri coinvolti in un'operazione devono essere dello stesso tipo. Se ad esempio cambiassimo la riga let prezzo = 1000.0;
in let prezzo = 1000;
, il numero 1000 verrebbe trattato come un intero e la formula che segue di alcune righe sortirebbe l'errore:
error[E0277]: cannot multiply `{integer}` by `{float}`
Il simbolo = è l'operatore di assegnazione usato per inizializzare, in questo caso, una nuova variabile con il risultato del calcolo. Esistono anche forme miste di operatori di assegnazione con i quali svolgiamo un'operazione e ne riponiamo il risultato nella stessa variabile coinvolta :
- += per cui a+=5 equivale a a=a+5;
- -= per cui a-=5 equivale a a=a-5;
- *= per cui a*=5 equivale a a=a*5;
- /= per cui a/=5 equivale a a=a/5;
- %= per cui a%=5 equivale a a=a%5.
Non li mettiamo ancora in pratica in quanto le variabili sono immutabili in Rust di default quindi aspetteremo di imparare ad usare mut
per sperimentarli. Al contrario di altri linguaggi, non esistono gli operatori unari, sia postfissi che prefissi, quindi non potremo eseguire incrementi o decrementi di 1 con ++
e --
.
Operatori di confronto
Per confrontare valori esistono i classici operatori che si usano per confronti e cicli:
- >, il maggiore;
- <, il minore;
- >=, maggiore o uguale;
- <=, minore o uguale;
- ==, uguale;
- !=, diverso;
I risultati di questi operatori sono sempre booleani come dimostra il seguente programmino:
fn main() {
println!("5 maggiore di 3 ... {}",5>3);
println!("5 minore di 3 ... {}",5<3);
println!("5 maggiore o uguale di 3 ... {}",5>=3);
println!("5 minore o uguale di 3 ... {}",5<=3);
println!("5 uguale a 3 ... {}",5==3);
println!("5 diverso da 3 ... {}",5!=3);
}
il quale genera:
5 maggiore di 3 ... true
5 minore di 3 ... false
5 maggiore o uguale di 3 ... true
5 minore o uguale di 3 ... false
5 uguale a 3 ... false
5 diverso da 3 ... true
Gli operatori di confronto completano il loro senso con quelli logici che permetteranno di combinare più confronti tra loro, producendo ancora dei valori booleani. Essi sono:
- &&, AND logico che restituisce vero solo se i due termini messi in rapporto sono entrambi veri;
- ||, OR logico per il quale il risultato è sempre vero a meno che entrambi i termini siano falsi;
- !, NOT che inverte il valore booleano di un termine restituendo vero se applicato al falso e viceversa.
Ecco qualche esempio. Se vogliamo verificare se la variabile a
ha un valore compreso tra 10 e 20 (inclusi) possiamo utilizzare (a>=10) && (a<=20).
L'operazione (a==10) || (a==20)
verificherà che il contenuto della variabile corrisponda precisamente a 10 o a 20. Mentre per verificare se il suo valore è esterno all'intervallo che va da 10 a 20 (inclusi) basterà applicare il NOT al primo esempio, !((a>=10) && (a<=20)).
, o crearne una versione con l'OR. Ecco alcuni esempi:
fn main() {
let a=16;
println!("a compresa tra 10 e 20 ... {}",(a>=10) && (a<=20));
println!("a esterno all'intervallo [10-20] ... {}",!((a>=10) && (a<=20)));
println!("a esterno all'intervallo [10-20] ... {}",(a<10) || (a>20));
}
e questo è ciò che si ottiene eseguendolo:
a compresa tra 10 e 20 ... true
a esterno all'intervallo [10-20] ... false
a esterno all'intervallo [10-20] ... false
Operatori bitwise
L'informazione sappiamo che è memorizzata in byte, a loro volta composti da bit. A questi ultimi viene attribuito un valore logico corrispondente a 0 o 1. Agendo sui singoli bit possiamo modificare i valori al loro interno e per farlo esistono appositi operatori il cui funzionamento ricorda quello degli operatori logici. Vediamo quali sono:
- &, AND, operazione bit a bit dove il risultato sarà 1 solo se applicato a due bit entrambi impostati a 1;
- |, OR, il risultato sarà 0 solo se applicato a due bit impostati entrambi a 0, altrimenti darà sempre 1;
- ^, XOR, è un OR esclusivo che restituisce 1 solo se i due bit a cui viene applicato sono diversi;
- !, NOT, inverte il valore dei bit;
- >>, shift a destra, fa scorrere i bit a destra di un numero specificato di posizioni;
- <<, shift a sinistra, fa scorrere i bit a sinistra di un numero specificato di posizioni.
Possiamo proporre una piccola dimostrazione utilizzando la capacità di println!
di stampare dati in formato binario. Sarà sufficiente inserire tra le parentesi graffe segnaposto l'indicazione :b
per richiedere la visualizzazione dei valori dei singoli bit e con l'inserimento di 08
chiederemo di colmare con degli 0 le posizioni mancanti per arrivare a 8 elementi. Vediamo le operazioni bitwise applicate al numero 232:
fn main() {
let a=232u8;
println!("{} in binario è {:08b}", a, a);
println!("a & 8 lascia attivo solo il 4° bit da destra ... {:08b}", a & 8);
println!("a | 2 attiva il 2° bit da destra ... {:08b}", a | 2);
println!("!a inverte tutti i bit ... {:08b}", !a);
println!("a >> 2 scala i bit a destra di 2 posizioni ... {:08b}", a >> 2);
println!("a << 2 scala i bit a sinistra di 2 posizioni ... {:08b}", a << 2);
}
e questo è l'output prodotto:
232 in binario è 11101000
a & 8 lascia attivo solo il 4° bit da destra ... 00001000
a | 2 attiva il 2° bit da destra ... 11101010
!a inverte tutti i bit ... 00010111
a >> 2 scala i bit a destra di 2 posizioni ... 00111010
a << 2 scala i bit a sinistra di 2 posizioni ... 10100000