Lua/Librerie standard

Indice del libro

In gergo da programmatori, si dice che Lua sia un linguaggio "senza batterie incluse": significa che le sue librerie sono ridotte al minimo necessario per svolgere alcune operazioni. Lua si affida alla sua comunità per creare librerie che possono essere utilizzate per eseguire attività più specifiche. Il Lua Reference Manual fornisce documentazione per tutte le librerie,[1] che quindi di seguito saranno descritte solo brevemente. Tutte le librerie, eccetto le librerie di base e quelle dei pacchetti, forniscono le loro funzioni e i loro valori come campi di una tabella.

Libreria di base

La libreria di base fornisce le funzionalità di base a Lua. Tutte le sue funzioni e i suoi valori sono direttamente disponibili nell'ambiente globale, e tutte le funzioni e i valori disponibili direttamente nell'ambiente globale per impostazione predefinita fanno parte della libreria di base.

Asserzioni

Un'asserzione (assertion) è un predicato che lo sviluppatore assume come vero. Sono utilizzate nei programmi per garantire che una condizione specifica sia vera in un momento specifico dell'esecuzione di un programma. Le asserzioni vengono utilizzate nei test unitari per verificare che un programma funzioni correttamente, ma vengono impiegate anche nel codice del programma. In questo caso, il programma fallirà se un'asserzione risulta falsa, sia per controllare che l'ambiente in cui il programma viene eseguito sia corretto, sia per verificare che non siano stati commessi errori nel codice. Inoltre, generano messaggi di errore appropriati per facilitare l'individuazione dei bug quando qualcosa non avviene come previsto. In Lua, le asserzioni sono fatte con la funzione assert, che accetta come parametri una condizione e un messaggio (che verrà impostato di default su "assertion failed!"). Quando la condizione viene valutata come falsa, assert genera un errore con il messaggio. Quando viene valutata come vera, assert restituisce tutti i suoi argomenti.

Garbage collection

La garbage collection è una forma di gestione automatica della memoria implementata da Lua e molti altri linguaggi. Quando un programma deve memorizzare dati in una variabile, chiede al sistema operativo di allocare spazio nella memoria del computer per memorizzare il valore della variabile. Quindi, quando non ha più bisogno dello spazio (generalmente perché la variabile è uscita dall'ambito), dice al sistema operativo di deallocare lo spazio in modo che un altro programma possa usarlo. In Lua, il processo è molto più complesso, ma l'idea di base è la stessa: il programma deve dire al sistema operativo quando non ha più bisogno del valore di una variabile. Nei linguaggi di basso livello, l'allocazione è gestita dal linguaggio, ma la deallocazione no perché il linguaggio non può sapere quando un programmatore non ha più bisogno di un valore: anche se una variabile che faceva riferimento al valore è uscita dall'ambito o è stata rimossa, un'altra variabile o un campo in uno script potrebbe comunque farvi riferimento e deallocarla causerebbe problemi. Nei linguaggi di livello superiore, la deallocazione può essere gestita da vari sistemi di gestione automatica della memoria, come la garbage collection, che è il sistema utilizzato da Lua. Il garbage collector cerca regolarmente tra tutti i valori allocati da Lua per valori che non sono referenziati da nessuna parte. Raccoglierà valori a cui il programma non può più accedere (perché non vi è alcun riferimento) e, poiché sa che questi valori possono essere deallocati in modo sicuro, li deallocherà. Tutto ciò avviene in modo trasparente e automatico, quindi il programmatore in genere non deve fare nulla al riguardo. Tuttavia, a volte, lo sviluppatore potrebbe voler dare istruzioni al garbage collector.

Riferimenti deboli

I riferimenti deboli (weak references) sono riferimenti ignorati dal garbage collector. Questi riferimenti sono indicati al garbage collector dallo sviluppatore, tramite il metametodo mode. Il metametodo mode di una tabella dovrebbe essere una stringa. Se quella stringa contiene la lettera k, tutte le chiavi dei campi della tabella sono deboli, e se contiene la lettera v, tutti i valori dei campi della tabella sono deboli. Quando un array di oggetti ha valori deboli, il garbage collector raccoglierà questi oggetti anche se sono referenziati in quell'array, fintanto che sono referenziati solo in quell'array e in altri riferimenti deboli. Questo comportamento è a volte utile, ma raramente utilizzato.

Manipolazione del garbage collector

Il garbage collector può essere manipolato con la funzione collectgarbage, che fa parte della libreria di base e funge da interfaccia per il garbage collector. Il suo primo argomento è una stringa che indica al garbage collector quale azione deve essere eseguita; un secondo argomento è utilizzato da alcune azioni. La funzione collectgarbage può essere utilizzata per arrestare il garbage collector, eseguire manualmente cicli di raccolta e contare la memoria utilizzata da Lua.

Coroutine

« Le coroutine sono componenti di programmi per computer che generalizzano le subroutine per consentire più punti di ingresso per sospendere e riprendere l'esecuzione in determinate posizioni. Le coroutine sono adatte per implementare componenti di programmi più familiari come task cooperativi, eccezioni, cicli di eventi, iteratori, elenchi infiniti e pipe. »
(Wikipedia, voce Coroutine)

Le coroutine sono componenti che possono essere create e manipolate con la libreria coroutine in Lua e che consentono di cedere e riprendere l'esecuzione di una funzione in posizioni specifiche chiamando funzioni che cederanno la coroutine dall'interno di se stessa o che la riprenderanno dall'esterno di se stessa. Di seguito forniamo alcuni esempi.

  1. Una funzione nel thread principale crea una coroutine da una funzione con coroutine.create e la riprende con coroutine.resume, a cui viene passato il numero 3.
  2. La funzione nella coroutine viene eseguita e ottiene il numero passato e coroutine.resume argomento.
  3. La funzione arriva a un certo punto della sua esecuzione in cui chiama coroutine.yield con, come argomento, la somma dell'argomento ricevuto (3) e 2 (quindi, 3+2=5).
  4. La chiamata a coroutine.resume restituisce 5, perché è stata passata a coroutine.yield, e il thread principale, ora di nuovo in esecuzione, memorizza quel numero in una variabile. Riprende la coroutine dopo aver eseguito del codice, passando a coroutine.resume il doppio del valore che ha ricevuto dalla chiamata a coroutine.resume (ad esempio passa 5×2=10).
  5. La coroutine ottiene il valore passato a coroutine.resume come risultato della chiamata a coroutine.yield e termina dopo aver eseguito altro codice. Restituisce la differenza tra il risultato della chiamata a coroutine.yield e il valore che le era stato dato inizialmente come parametro (ad esempio 10−3=7).
  6. Il thread principale ottiene il valore restituito dalla coroutine come risultato della chiamata coroutine.resume e prosegue.

Questo esempio, inserito nel codice, fornisce quanto segue:

local co = coroutine.create(function(initial_value)
	local value_obtained = coroutine.yield(initial_value + 2) -- 3+2=5
	return value_obtained - initial_value -- 10-3=7
end)

local _, initial_result = coroutine.resume(co, 3) -- initial_result: 5
local _, final_result = coroutine.resume(co, initial_result * 2) -- 5*2=10
print(final_result) --> 7

La funzione coroutine.create crea una coroutine da una funzione; le coroutine sono valori di tipo thread. coroutine.resume avvia o continua l'esecuzione di una coroutine. Una coroutine è detta morta quando ha incontrato un errore o non ha più nulla da eseguire (nel qual caso ha terminato la sua esecuzione). Quando una coroutine è morta, non può essere ripresa. La funzione coroutine.resume restituirà true è stata completata con successo, insieme a tutti i valori restituiti, sia in caso di fine della coroutine, sia se questa è stata sospesa tramite coroutine.yield. Se l'esecuzione non è andata a buon fine, restituirà false accompagnato da un messaggio di errore. Inoltre, coroutine.resume restituisce la coroutine in esecuzione e true se quella coroutine è il thread principale, oppure false in caso contrario.

La funzione coroutine.status restituisce lo stato di una coroutine come stringa:

  • "running" se la coroutine è in esecuzione, il che significa che deve essere la coroutine che ha chiamato coroutine.status;
  • "suspended" se la coroutine è sospesa in una chiamata a yield o se non è ancora iniziata l'esecuzione;
  • "normal" se la coroutine è attiva ma non in esecuzione, il che significa che ha ripreso un'altra coroutine;
  • "dead" se la coroutine ha terminato l'esecuzione o ha riscontrato un errore.

La funzione coroutine.wrap restituisce una funzione che riprende una coroutine ogni volta che viene chiamata. Gli argomenti extra forniti a questa funzione fungeranno da argomenti extra per coroutine.resume e i valori restituiti dalla coroutine o passati a coroutine.yield saranno restituiti da una chiamata alla funzione. La funzione coroutine.wrap, a differenza di coroutine.resume, non chiama la coroutine in modalità protetta e propaga errori.

Esistono numerosi casi d'uso per le coroutine, ma la loro descrizione esula dallo scopo di questo libro.

Corrispondenza delle stringhe

Quando si manipolano stringhe è spesso utile poter cercare sottostringhe che seguono un certo modello (pattern). Lua ha una libreria di manipolazione di stringhe che offre funzioni per farlo, e una notazione per esprimere modelli che le funzioni possono cercare nelle stringhe. La notazione offerta da Lua è molto simile alle espressioni regolari, una notazione per esprimere modelli utilizzata dalla maggior parte dei linguaggi e degli strumenti nel mondo della programmazione. Tuttavia, è più limitata e ha una sintassi leggermente diversa.

La funzione find della libreria string cerca la prima corrispondenza di un modello in una stringa. Se trova un'occorrenza del modello nella stringa, restituisce gli indici nella stringa (numeri interi che rappresentano la posizione dei caratteri nella stringa a partire dal primo carattere, che è in posizione 1) dove l'occorrenza inizia e finisce. Se non trova un'occorrenza del modello, non restituisce nulla. Il primo parametro che accetta è la stringa, il secondo è il modello e il terzo è un numero intero che indica la posizione del carattere in cui la funzione find dovrebbe iniziare la ricerca. Infine, alla funzione find può essere detto di eseguire una corrispondenza semplice senza modello fornendo il valore true come quarto argomento. Quindi cercherà semplicemente un'occorrenza della seconda stringa che le viene fornita nella prima stringa. Il terzo argomento deve essere fornito quando viene eseguita una corrispondenza semplice. Questo codice di esempio cerca la parola "lazy" in una frase e stampa le posizioni di inizio e fine dell'occorrenza che trova della parola:

local start_position, end_position = string.find("The quick brown fox jumps over the lazy dog.", "lazy", 1, true)
print("The word \"lazy\" was found starting at position " .. start_position .. " and ending at position " .. end_position .. ".")

Questo codice fornisce il risultato La parola "lazy" è stata trovata a partire dalla posizione 36 e fino alla posizione 39.. Equivale a quanto segue:

local sentence = "The quick brown fox jumps over the lazy dog."
local start_position, end_position = sentence:find("lazy", 1, true)
print("The word \"lazy\" was found starting at position " .. start_position .. " and ending at position " .. end_position .. ".")

Ciò funziona perché il metametodo index delle stringhe è impostato sulla tabella contenente le funzioni della libreria string, rendendo possibile la sostituzione string.a(b, ...) con b:a(...).

Le funzioni nella libreria string che accettano indici per indicare la posizione del carattere o che restituiscono tali indici considerano il primo carattere come se si trovasse nella posizione 1. Accettano numeri negativi e li interpretano come indici all'indietro, dalla fine della stringa, con l'ultimo carattere in posizione -1.

I pattern sono stringhe che seguono una certa notazione per indicare uno schema che una stringa può corrispondere o meno. A questo scopo, i pattern contengono classi di caratteri, combinazioni che rappresentano insiemi di caratteri.

Combinazione di caratteriDescrizione
.Tutti i caratteri
%aLettere (maiuscole e minuscole)
%cCaratteri di controllo
%dCifre
%gCaratteri stampabili (tranne lo spazio)
%lLettere minuscole
%pCaratteri di punteggiatura
%sSpazi
%uLettere maiuscole
%wCaratteri alfanumerici (cifre e lettere)
%xCifre esadecimali

Tutti i caratteri non speciali rappresentano se stessi, mentre i caratteri speciali (tutti i caratteri che non sono alfanumerici) possono essere sottoposti a escape tramite un prefisso di percentuale. Le classi di caratteri possono essere combinate per creare classi di caratteri più grandi inserendole in un set. I set sono indicati come classi di caratteri indicate tra parentesi quadre (ad esempio, [%xp] è il set di tutti i caratteri esadecimali più la lettera "p"). Gli intervalli di caratteri possono essere indicati separando i caratteri finali dell'intervallo, in ordine crescente, con un trattino (ad esempio, [0-9%s] rappresenta tutte le cifre da 0 a 9 più gli spazi). Se il carattere di accento circonflesso ("^") viene inserito all'inizio del set (subito dopo la parentesi quadra di apertura), il set conterrà tutti i caratteri eccetto quelli che avrebbe contenuto se quel accento circonflesso non fosse stato inserito all'inizio del set.

Il complemento di tutte le classi rappresentate da una lettera preceduta da un segno di percentuale può essere indicato come un segno di percentuale seguito dalla lettera maiuscola corrispondente (vale a dire che %S rappresenta tutti i caratteri eccetto gli spazi).

I modelli sono sequenze di elementi modello che rappresentano quali sequenze devono essere trovate nel modello affinché una stringa vi corrisponda. Un elemento modello può essere: una classe di caratteri, nel qual caso corrisponde a uno qualsiasi dei caratteri della classe una sola volta; una classe di caratteri seguita dal carattere "*", nel qual caso corrisponde a zero o più ripetizioni dei caratteri della classe (questi elementi di ripetizione corrisponderanno sempre alla sequenza più lunga possibile); una classe di caratteri seguita dal carattere "+", nel qual caso corrisponde a una o più ripetizioni dei caratteri della classe (anche in questo caso, questi elementi di ripetizione corrisponderanno sempre alla sequenza più lunga possibile); una classe di caratteri seguita dal carattere "-", nel qual caso corrisponde a zero o più ripetizioni dei caratteri della classe, ma questa volta corrisponde alla sequenza più breve possibile; una classe di caratteri seguita dal punto interrogativo ("?"), nel qual caso corrisponde a una o nessuna occorrenza di un carattere della classe.

È possibile far corrispondere sottostringhe equivalenti a sottostringhe catturate in precedenza: %1 corrisponderà alla prima sottostringa catturata, %2 alla seconda e così via fino a %9. Le catture sono descritte di seguito. Ci sono altre due funzionalità offerte dai modello, come descritto dal manuale di riferimento:

« %bxy, dove x e y sono due caratteri distinti; tale elemento corrisponde a stringhe che iniziano con x, finiscono con y, e dove x e y sono bilanciate. Ciò significa che, se si legge la stringa da sinistra a destra, contando +1 per una x e -1 per una y, la y finale è la prima y in cui il conteggio raggiunge 0. Ad esempio, l'elemento %b() corrisponde a espressioni con parentesi bilanciate. %f[set], un modello di frontiera; tale elemento corrisponde a una stringa vuota in qualsiasi posizione in modo che il carattere successivo appartenga a set e il carattere precedente non appartenga a set. Il set set viene interpretato come descritto in precedenza. L'inizio e la fine del soggetto vengono gestiti come se fossero il carattere '\0'. »
(Lua 5.2 Reference Manual)

I modelli sono sequenze di elementi del modello, possono essere preceduti da un accento circonflesso, che indica che il modello può corrispondere solo all'inizio della stringa, e possono essere seguiti da un simbolo di dollaro, che indica che il modello può corrispondere solo alla fine della stringa. Si dice che questi simboli ancorano la corrispondenza all'inizio o alla fine della stringa. Questi due caratteri hanno un significato speciale solo quando si trovano all'inizio o alla fine di un modello.

I sotto-modelli possono essere racchiusi tra parentesi all'interno di modello per indicare le catture. Quando una corrispondenza riesce, le sottostringhe della stringa che corrispondono alle catture vengono memorizzate per un uso futuro, ad esempio per essere restituite da gmatch. Sono sempre numerate a partire dalla posizione della loro parentesi sinistra. Due parentesi vuote indicano la cattura vuota, che cattura la posizione corrente della stringa (che è un numero e non fa parte della stringa).

La funzione gmatch può essere utilizzata per scorrere le occorrenze di un modello in una stringa; non è possibile, a differenza della funzione find, specificare una posizione iniziale per iniziare la ricerca o per eseguire una semplice corrispondenza. La funzione gmatch restituisce un iteratore che, quando chiamato, restituisce le catture successive dal modello specificato nella stringa. L'intera corrispondenza viene invece fornita se non ci sono catture specificate nel modello. L'esempio seguente mostra come scorrere le parole in una frase e stamparle una alla volta:

local sentence = "La volpe marrone salta veloce sopra il cane pigro."
for word in sentence:gmatch('%a+') do
	print(word)
end

In questo esempio, l'intera corrispondenza è data dall'unico valore restituito dall'iteratore, word .

La funzione gsub può essere utilizzata per sostituire tutte le occorrenze di un modello in una stringa con qualcos'altro. I suoi primi due argomenti sono la stringa e il modello, mentre il terzo è la stringa con cui sostituire le occorrenze e il quarto è il numero massimo di occorrenze che devono essere sostituite. Il terzo argomento, invece di essere una stringa, può anche essere una tabella o una funzione.

Quando il terzo argomento è una stringa, viene chiamata stringa di sostituzione e sostituisce le occorrenze del modello nella stringa. Le catture memorizzate dal modello possono essere incorporate nella stringa di sostituzione; sono contrassegnate da un segno di percentuale seguito da una cifra che rappresenta il numero della cattura. La corrispondenza stessa può essere rappresentata da %0. I segni di percentuale nelle stringhe di sostituzione devono essere sottoposti a escape come %%.

Quando il terzo argomento è una tabella, la prima cattura viene usata come chiave per indicizzare quella tabella e la stringa di sostituzione è il valore corrispondente a quella chiave nella tabella. Quando è una funzione, quella funzione viene chiamata per ogni corrispondenza, con tutte le catture passate come argomenti. In entrambi i casi, se non c'è cattura, viene usata l'intera corrispondenza. Se la funzione o la tabella fornisce il valore false o nil, non viene eseguita alcuna sostituzione.

Ecco alcuni esempi tratti direttamente dal Lua 5.2 Reference Manual:[2]

x = string.gsub("hello world", "(%w+)", "%1 %1")
--> x="hello hello world world"

x = string.gsub("hello world", "%w+", "%0 %0", 1)
--> x="hello hello world"

x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
--> x="world hello Lua from"

x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)
--> x="home = /home/roberto, user = roberto"

x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
      return load(s)()
    end)
--> x="4+5 = 9"

local t = {name="lua", version="5.2"}
x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t)
--> x="lua-5.2.tar.gz"

Lua offre altre funzioni per manipolare le stringhe oltre a quelle per il modello matching. Queste includono: la funzione reverse, che restituisce una stringa con l'ordine dei caratteri invertito; la funzione lower, che restituisce l'equivalente minuscolo di una stringa; la funzione upper, che restituisce l'equivalente maiuscolo di una stringa; la funzione len, che restituisce la lunghezza di una stringa; la funzione sub, che restituisce la sottostringa di una stringa che inizia e finisce nelle due posizioni dei caratteri fornite come argomenti. Ce ne sono altre e la loro documentazione può essere trovata nel Reference Manual.

Note

  1. Roberto Ierusalimschy, Waldemar Celes e Luiz Henrique de Figueiredo, Lua 5.2 Reference Manual. Categoria:Errori del modulo citazione - citazioni che usano parametri non supportatiCategoria:Errori del modulo citazione - citazioni che usano parametri non supportati
  2. Lua 5.2 Reference Manual

Categoria:Moduli 75%25

Categoria:Lua#Librerie%20standard
Categoria:Errori del modulo citazione - citazioni che usano parametri non supportati Categoria:Lua Categoria:Moduli 75%