Home Rhyylen
Contatto
 
 
 
Rust Language
Capitolo 4
Booleani

I valori di tipo booleano, nella loro semplicità, sono tra i grandi protagonisti della programmazione. Si tratta tra l'altro, come evidenziato nel capitolo precedente, di uno dei tipi primitivi, built-in, del linguaggio. In Rust i valori ammessi sono due, come in molti altri linguaggi:

   * true
   * false

vero e falso. Una variabile booleana si dichiara nel solito modo:

let b1 = true:
let b2: bool = false;
let mut b3 = true;


non sono ammessi altri valori ad esempio valori 0 e 1 che in altri linguaggi possono sostituirsi a true e false non sono consentiti. Questo è un bene. Vedremo comunque un esempio in fine paragrafo che chiarirà ulteriormente il rapporto tra interi e booleani. Come sempre, affinchè dette variabili siano modificabili è necessario che sia presente la solita keyword mut. Annotiamo che dal punto di vista tecnico una variabile booleana occupa lo spazio di un solo byte. In pratica basterebbe un bit ma in questo modo è possibile creare dei puntatori anche verso variabili booleane.
Ora, una variabile dichiarata come negli esempi precedenti piuttosto raramente vi tornerà utile. Invece, nella maggioranza dei casi il valore booleano che tratterete sarà il risultato di una espressione ovvero una operazione di confronto. Vediamo quali sono gli operatori usati e chiariamo il concetto con un esempio:

== uguaglianza
> maggiore
< minore
>= maggiore o uguale
<= minore o uguale
!= diverso

 Questi operatori danno origine ad espressioni il cui valore deve essere necessariamente vero o falso. Vediamo il seguente esempio:

  Esempio 4.1
1
2
3
4
5
6
fn main() {
    println!("{}", 3 > 0);
    println!("{}", 2 == 2);
    println!("{}", 'a' == 'b');
    println!("{}", 3 != 7);
}

che restituisce il seguente output:

true
true
false
true

Quando ci occuperemo delle istruzioni di selezione, che possono presentare naturalmente le più svariate casistiche, vedremo quanto importanti siano questi operatori.
Sui valori booleani, true e false, è possibile compiere delle operazioni di carattere logico. Gli operatori principali sono i seguenti:
  • and    espresso come &&
  • or     espresso come ||
  • not    espresso come !
  • xor    espresso come ^
  • uguale espresso come ==
l'ultimo lo abbiamo già incontrato ma ora lo vediamo in una luce diversa. Il comportamento di questi operatori può essere espresso attraverso tabelle specifiche:

and
true  and true   -> true
true  and false  -> false
false and true   -> false
false and false  -> false

or
true  or true   -> true
true  or false  -> true
false or true   -> true
false or false  -> false

not
not true  -> false
not false -> true

xor
true  xor true   -> false
true  xor false  -> true
false xor true   -> true
false xor false  -> false

==
true  == true   -> true
false == true   -> false
true  == false  -> false
false == false  -> true

Il tipo bool essendo, come detto, primitivo in Rust implementa 5 trait fondamentali (oltre ad altri ancora): Clone, Copy, Sized, Send, Sync. Cosa questo significhi in dettaglio è materia molto più avanzata, per il momento diciamo che grazie al primo, siamo in grado di effetturare delle copie bit a bit. Il seguente codice crea due variabili booleane b1 e b2 che è copia di b1 ma da essa indipendente.

fn main() {
    let mut b1 = true;
    let mut b2 = b1;
    b1 = false;
    print!("{}", b2);
}

b2 continua valere "true" mentre b1 è passato a false. Quindi b2 è del tutto staccato e indipendente da b1.

Abbiamo detto che non è ammesso che valori numerici siano direttamente usati come booleani. E' tuttavia possibile effettuare una conversione da booleano ad intero mentre non è ammesso il contrario:

  Esempio 4.2
1
2
3
4
5
fn main() {
    println!("{}", false as i32);
    println!("{}", true as i32);
//  println!("{}", 1 as bool); questa non compila
}

se escludiamo la riga 5, l'output è:

0
1

mentre reintroducendo la 5 si otterrebbe:

error[E0054]: cannot cast `i32` as `bool`

chiaro e forte. Quindi possiamo andare dai booleani verso gli interi ma non viceversa.

Per quanto non utile nel nostro contesto segnalo anche la presenza di un crate che si chiama as_bool e fornisce un modo per rappresentare vari tipi in un contesto booleano. Esso si basa su una serie di regole:
  • I booleani si comportano come previsto (true è vero, false è falso).
  • Tutti i numeri non zero sono veri.
  • Le stringhe non vuote sono vere, mentre le stringhe vuote sono false.
  • Le collezioni non vuote sono vere, mentre le collezioni vuote sono false.
  • None è sempre falso, mentre Some è valutato in base al contenuto.

Il suo uso, che necessita di qualche manipolazione un po' particolare, che fa necessariamente uso del file cargo.toml, esula da questa trattazione ma lo vedremo nella sezione degli esempi.

I booleani internamente sono più complessi di quanto sembri e su di essi è possibile effettuare ulteriori manipolazioni (per fare un esempio i classici BitAnd e BitOr grazie ai trait omologhi che questo tipo implementa)  che però esulano dalla finalità di base di questo paragrafo.