Vai al contenuto

Lua/Espressioni

Wikibooks, manuali e libri di testo liberi.
< Lua
Indice del libro

Come spiegato in precedenza, le espressioni sono pezzi di codice che hanno un valore e che possono essere valutate. Non possono essere eseguite direttamente (a eccezione delle chiamate di funzione) e quindi uno script che contenesse solo il seguente codice, che consiste in un'espressione, sarebbe errato:

3  +  5 
-- Il codice sopra è errato perché contiene solo un'espressione. 
-- Il computer non può eseguire '3 + 5', perché non ha senso.

Il codice deve essere composto da una sequenza di istruzioni. Queste istruzioni possono contenere espressioni che rappresentano i valori su cui l'istruzione deve operare o che deve utilizzare per eseguire l'operazione.

Alcuni esempi di codice presenti in questo capitolo non costituiscono codice valido, perché sono formati solo da espressioni. Nel prossimo capitolo saranno trattate le istruzioni e si potrà quindi iniziare a scrivere codice valido.

Valutare un'espressione significa calcolarla per trovarne il valore. Il valore a cui un'espressione viene valutata può variare a seconda del contesto, poiché può dipendere dall'ambiente di esecuzione e dal livello della pila (stack). Questo valore a volte sarà un numero, altre volte un testo, e altre ancora uno dei tanti tipi di dati disponibili, motivo per cui si dice che ha un tipo.

In Lua, e nella programmazione in generale, le espressioni sono solitamente composte da uno o più valori con zero o più operatori. Alcuni operatori possono essere utilizzati solo con alcuni tipi (sarebbe illogico, ad esempio, eseguire una divisione matematica su un testo, mentre ha senso dividere i numeri). Esistono due tipi di operatori: operatori unari e operatori binari. Gli operatori unari sono operatori che accettano solo un valore. Ad esempio, l'operatore unario - accetta solo un numero come parametro: -5, -3, -6, ecc. Più precisamente, accetta un numero come parametro e nega quel numero. L'operatore binario -, invece, che è un operatore diverso dal precedente, accetta due valori e sottrae il secondo dal primo: 5 - 3, 8 - 6, 4 - 9, ecc.

È possibile ottenere il tipo di un numero come stringa con la funzione type:

print(type(32425)) --> number

I numeri in genere rappresentano delle quantità, ma possono essere usati per molte altre cose. Il tipo number in Lua funziona per lo più nello stesso modo dei numeri reali. I numeri possono essere costruiti come numeri interi, numeri decimali, esponenti decimali o anche in esadecimale. Ecco alcuni numeri validi:

  • 3
  • 3.0
  • 3.1416
  • 314.16e-2
  • 0.31416E1
  • 0xff
  • 0x56

Operazioni aritmetiche

[modifica | modifica sorgente]

Gli operatori per i numeri in Lua sono i seguenti:

Operazione Sintassi Descrizione Esempio Risultato
Inverso additivo -a Cambia il segno di a e restituisce il valore -3.14159
Addizione a + b Restituisce la somma di a e b 5.2 + 3.6 8.8
Sottrazione a - b Sottrae b da a e restituisce il risultato 6.7 - 1.2 5.5
Moltiplicazione a * b Restituisce il prodotto di a e b 3.2 * 1.5 4.8
Potenza a ^ b Restituisce a alla potenza b 5 ^ 2 25
Divisione a / b Divide a per b e restituisce il risultato 6.4 / 2 3.2
Divisione intera a // b Divide a per b e restituisce la parte intera del risultato 6.4 // 2 3
Modulo a % b Restituisce il resto della divisione di a per b 5 % 3 2

Probabilmente conosci già tutti questi operatori (corrispondono agli operatori matematici di base) tranne l'ultimo. L'ultimo è chiamato modulo e calcola semplicemente il resto della divisione di un numero per un altro. 5 % 3, ad esempio, darebbe 2 come risultato perché 2 è il resto della divisione di 5 per 3. L'operatore modulo è meno comune degli altri operatori, ma ha molteplici usi.

Un sottotipo di number, gli interi (integers), è stato aggiunto in Lua 5.3. I numeri possono essere interi o in virgola mobile. I numeri in virgola mobile (float) sono simili ai numeri descritti sopra, mentre gli interi sono numeri senza parte decimale. La divisione in virgola mobile / e l'elevamento a potenza convertono sempre i loro operandi in numeri in virgola mobile, mentre tutti gli altri operatori danno interi se i loro due operandi erano interi. In altri casi, a eccezione dell'operatore di divisione intera (floor division) //, il risultato è un numero in virgola mobile.

Nil è il tipo del valore nil, la cui principale caratteristica è essere diverso da qualsiasi altro valore; di solito rappresenta l'assenza di un valore significativo. Ecco alcuni esempi di cose che hanno il valore nil:

  • valore delle variabili a cui accedi prima di assegnare loro un valore;
  • valore che si ottiene quando si tenta di accedere a una variabile al di fuori del suo ambito;
  • valore per qualsiasi chiave in una tabella che non è stata assegnata;
  • valore restituito da tonumber se non riesce a convertire una stringa in un numero.

Su un livello più avanzato, l'assegnazione intenzionale di un valore nil rimuove il riferimento a una variabile o a una tabella e consente al garbage collector di recuperare la sua memoria.

Un valore booleano può essere vero o falso, ma nient'altro. In Lua è scritto come true e false, che sono parole chiave riservate. È importante notare che qui nil è un tipo di dato diverso da quello indicato in precedenza. and, or, not() sono solitamente associati a valori booleani, ma possono essere usati con qualsiasi tipo di dato in Lua.

Operazione Sintassi Descrizione
Negazione booleana not a Se a è falso o nullo, restituisce true. Altrimenti, restituisce false.
Congiunzione logica a and b Restituisce il primo argomento se è falso o nullo. Altrimenti, restituisce il secondo argomento.
Disgiunzione logica a or b Restituisce il primo argomento se non è né falso né nullo. Altrimenti, restituisce il secondo argomento.

In sostanza, l'operatore not nega semplicemente il valore booleano (lo rende falso se è vero e lo rende vero se è falso), l'operatore and restituisce vero se entrambi sono veri e falso se non lo sono e l'operatore or restituisce vero se uno degli argomenti è vero e falso altrimenti. Tuttavia, non è esattamente così che funzionano, poiché il modo esatto in cui funzionano è spiegato nella tabella sopra. In Lua, i valori true e nil sono entrambi considerati falsi nelle espressioni logiche, mentre tutto il resto è considerato vero (anche 0 e le stringhe vuote).

Gli operatori relazionali introdotti nel prossimo capitolo (<, >, <=, >=, ~=, ==) non accettano necessariamente valori booleani come operandi, ma restituiranno sempre un valore booleano come risultato.

Questo può essere difficile da conciliare. Per maggiore chiarezza, ecco alcune tabelle di verità o coppie espressione-risultato. Qui x può essere nil, true o false:

Espressione Risultato
true and x x
false and x false
nil and x nil
true or x true
false or x x
nil or x x

Questo significa, in maniera un po' controintuitiva, che

Espressione Risultato
false and nil false
nil and false nil

Inoltre

Espressione Risultato
false == nil
nil == false
false
nil and false nil
Espressione Risultato
not(false)
not(nil)
true
not(true) false

Le stringhe (strings) sono sequenze di caratteri che possono essere utilizzate per rappresentare del testo. In Lua si possono scrivere tra virgolette doppie, virgolette singole o parentesi lunghe, che sono state trattate in precedenza nella sezione sui commenti (si noti che commenti e stringhe non hanno nulla in comune se non il fatto che possono essere entrambi delimitati da parentesi lunghe, precedute da due trattini nel caso dei commenti). Le stringhe che non sono contenute tra parentesi lunghe continueranno solo per una riga. Per questo motivo, l'unico modo per creare una stringa che contenga molte righe senza utilizzare parentesi lunghe è utilizzare caratteri di escape. Questo, in determinati casi, è anche l'unico modo per inserire virgolette singole o doppie. Le sequenze di escape sono costituite da due parti: un carattere di escape, che sarà sempre una barra rovesciata ('\') in Lua, e un identificatore che identifica il carattere da sottoporre a escape.

Sequenze di escape in Lua
Sequenza di escape Descrizione
\n Una nuova linea
\" Una doppia citazione
\' Una virgoletta singola (o apostrofo)
\\ Una barra rovesciata
\t Una linguetta orizzontale
\### ### deve essere un numero compreso tra 0 e 255. Il risultato sarà il carattere ASCII corrispondente.

Le sequenze di escape vengono utilizzate quando inserire il carattere direttamente nella stringa causerebbe un problema. Ad esempio, se hai una stringa di testo racchiusa tra virgolette doppie e deve contenere altre virgolette doppie, allora devi racchiudere la stringa in caratteri diversi o eseguire l'escape delle virgolette doppie. L'escape dei caratteri nelle stringhe delimitate da parentesi lunghe non è necessario, e questo vale per tutti i caratteri. Tutti i caratteri in una stringa delimitata da parentesi lunghe saranno presi così come sono. Il carattere % è utilizzato nei pattern di stringa per eseguire l'escape dei caratteri magici, ma in questo caso il termine escape viene utilizzato in un altro contesto.

"Questa è una stringa valida."

"Anche questa è una stringa valida."

"Questa è una stringa \" valida 'che contiene virgolette singole non sottoposte a escape e virgolette doppie sottoposte a escape."

[[ 
Questa è una riga che può continuare 
su più righe.

Può contenere virgolette singole, virgolette doppie e tutto il resto (-- compresi i commenti). Ignora tutto (compresi i caratteri di escape) eccetto le parentesi lunghe di chiusura dello stesso livello della parentesi lunga di apertura. 
]]

"Questa è una stringa valida che contiene tabulazioni \t, virgolette doppie \" e barre rovesciate \\ "

"Questa non " è una  stringa valida  perché al suo interno è presente una virgoletta doppia non protetta."

Per comodità, se una parentesi lunga di apertura è immediatamente seguita da una nuova riga, la nuova riga verrà ignorata. Pertanto, le due stringhe seguenti sono equivalenti:

[[Questa è una stringa 
che può continuare su più righe.]]

[[ 
Questa è una stringa 
che può continuare su più righe.]]

-- Poiché la parentesi lunga di apertura della seconda stringa è immediatamente seguita da una nuova riga, tale nuova riga viene ignorata.

È possibile ottenere la lunghezza di una stringa, come numero, utilizzando l'operatore di lunghezza unario ('#'):

print(#("Questa è una stringa")) --> 20

Concatenamento

[modifica | modifica sorgente]
« In linguaggio formale e programmazione software il concatenamento (o concatenazione) indica un procedimento in cui parole o numeri vengono legati insieme a formare, rispettivamente, una sola parola o numero. »
(Wikipedia, voce Concatenamento)

L'operatore di concatenamento delle stringhe in Lua è indicato da due punti ('..'). Ecco un esempio di concatenamento che concatena "pesce" e "cane" e stampa il risultato:

print("pesce" .. "cane") --> pescecane

Finora abbiamo descritto i quattro tipi base in Lua (numeri, booleani, nil e stringhe). Mancano ancora quattro altri tipi: funzioni, tabelle, userdata e thread. Le funzioni sono pezzi di codice che possono essere chiamati, che possono ricevere e restituire valori. Le tabelle sono strutture dati che possono essere utilizzate per la manipolazione dei dati. Gli userdata sono utilizzati internamente dalle applicazioni in cui è incorporato Lua per consentire a Lua di comunicare con quel programma tramite oggetti controllati dall'applicazione. Infine, i thread sono utilizzati dalle coroutine, che consentono a molte funzioni di essere eseguite contemporaneamente. Questi tipi saranno descritti più avanti.

I letterali sono notazioni per rappresentare valori fissi nel codice sorgente. Tutti i valori possono essere rappresentati come letterali in Lua, eccetto thread e userdata. I letterali stringa (letterali che valutano stringhe), ad esempio, sono costituiti dal testo che la stringa deve rappresentare racchiuso tra virgolette singole, virgolette doppie o parentesi lunghe. I letterali numerici, d'altro canto, sono costituiti dal numero che rappresentano espresso utilizzando la notazione decimale (es: 12.43), la notazione scientifica (es: 3.1416e-2 e 0.31416E1) o la notazione esadecimale (es: 0xff).

La coercizione è la conversione di un valore di un tipo di dati in un valore di un altro tipo di dati. Lua fornisce la coercizione automatica tra valori stringa e numeri. Qualsiasi operazione aritmetica applicata a una stringa tenterà di convertire questa stringa in un numero. Al contrario, ogni volta che è prevista una stringa e viene utilizzato un numero al suo posto, il numero verrà convertito in una stringa. Ciò si applica sia agli operatori Lua sia alle funzioni predefinite (funzioni fornite con il linguaggio).

print("122" + 1) --> 123
print("Il numero è " .. 5 .. ".") --> Il numero è 5.

La coercizione dei numeri in stringhe e delle stringhe in numeri può essere eseguita anche manualmente con le funzioni tostring e tonumber. La prima accetta un numero come argomento e lo converte in una stringa, mentre la seconda accetta una stringa come argomento e la converte in un numero (una base diversa da quella decimale predefinita può essere specificata nel secondo argomento).

Operazioni bit a bit

[modifica | modifica sorgente]

A partire da Lua 5.3, sono forniti operatori bit a bit (bitwise operators) per operare su numeri binari (pattern di bit). Questi operatori non sono usati con la stessa frequenza degli altri. Gli operatori bitwise in Lua operano sempre su interi, convertendo i loro operandi se necessario. Forniscono anche interi.

L'operazione bit a bit AND (con operatore &) esegue la congiunzione logica su ogni coppia di bit di due rappresentazioni binarie di uguale lunghezza. Ad esempio, 5 & 3 valuta 1. Possiamo spiegarlo osservando la rappresentazione binaria di questi numeri (gli indici sono usati per indicare la base):

Se i bit in una data posizione nella rappresentazione binaria di 5 e 3 sono 1 (come nel caso dell'ultimo bit), allora il bit in quella posizione sarà 1 nel risultato; in tutti gli altri casi, sarà 0.

L'operazione bit a bit OR (con operatore |) funziona nello stesso modo dell'AND, eseguendo la disgiunzione logica invece di eseguire la congiunzione logica. Quindi, 5 | 3 verrà valutato 7:

Qui possiamo vedere che il bit in ogni posizione nel risultato finale era 0 solo quando le rappresentazioni binarie dei due operandi avevano un bit 0 in quella posizione.

L'operazione bit a bit XOR (con operatore ~) funziona come le altre due, ma in una data posizione il bit finale è 1 solo se uno, e non entrambi, dei bit negli operandi è 1.

È lo stesso dell'esempio precedente, ma possiamo vedere che l'ultimo bit del risultato è 0 invece di 1, poiché l'ultimo bit di entrambi gli operandi era 1.

L'operazione bit a bit NOT (con operatore ~) esegue la negazione logica su ogni bit del suo operando univoco, il che significa che ogni 0 diventa 1 e che ogni 1 diventa 0. Pertanto, ~7 verrà valutato come -8:

In questo caso, il primo bit è diventato 1 nel risultato perché era 0 nell'operando, mentre gli altri bit sono diventati 0 perché erano tutti 1.

Spostamento a sinistraSpostamento a destra

Oltre a questi operatori bit a bit, Lua 5.3 supporta anche spostamenti aritmetici di bit. Lo spostamento a sinistra, con l'operatore << e illustrato a sinistra, consiste nello spostare tutti i bit a sinistra, di un numero di bit che corrisponde al secondo operando. Lo spostamento a destra, indicato dall'operatore code>>> e illustrato a destra, fa lo stesso ma nella direzione opposta.

Precedenza degli operatori

[modifica | modifica sorgente]

La precedenza degli operatori in Lua funziona come in matematica. Alcuni operatori saranno valutati prima di altri e le parentesi possono essere usate per cambiare arbitrariamente l'ordine in cui le operazioni devono essere eseguite. La priorità in cui gli operatori sono valutati è nell'elenco sottostante, dalla priorità più alta a quella più bassa. Alcuni di questi operatori non sono stati ancora discussi, ma saranno tutti trattati in questo libro.

  1. Potenza: ^
  2. Operatori unari: not, #, -, ~
  3. Operatori matematici di livello 2: *, /, //, %
  4. Operatori matematici di livello 1: +, -
  5. Concatenamento: ..
  6. Spostamenti di bit: <<, >>
  7. Bit a bit AND: &
  8. Bit a bit XOR: ~
  9. Bit a bit OR: |
  10. Operatori relazionali: <, >, <=, >=, ~=, ==
  11. Booleano and: and
  12. Booleano or: or