Sintassi

In Haxe, tutte le espressioni hanno lo stesso livello. Ciò significa che puoi innestarle insieme ricorsivamente senza alcun problema. Ad esempio : "tizio(if (x == 3) 5 else 8)". Come mostra l'esempio, significa anche che ogni espressione restituisce un valore di un tipo dato.

Constanti

I seguenti valori costanti possono essere usati:

0; // Int
-134; // Int
0xFF00; // Int

123.0; // Float
.14179; // Float
13e50; // Float
-1e-99; // Float

"hello"; // String
"hello \"world\" !"; // String
'hello "world" !'; // String

true; // Bool
false; // Bool

null; // Unknown<0>

~/[a-z]+/i; // EReg : espressione regolare

Ti accorgerai che null ha un valore speciale che può essere usato per ogni tipo, e ha un comportamento diverso da Dynamic. Sarà spiegato in dettaglio quando sarà introdotta l'inferenza dei tipi.

Operazioni

Le seguenti operazioni possono essere usate, in ordine di priorità:

  • v = e : assegna un valore ad una variabile, restituisce e
  • += -= *= /= %= &= |= ^= <<= >>= >>>= : assegna dopo aver eseguito l'operazione corrispondente
  • e1 || e2 : Se e1 è true allora true altrimenti valuta e2 . Sia e1 che e2 devono essere Bool.
  • e1 && e2 : Se e1 è false allora false altrimenti valuta e2 . Sia e1 che e2 devono essere Bool.
  • e1...e2 : Costruisce un iteratore intero (vedremo dopo a proposito degli Iteratori).
  • == != > < >= <= : esegue normali comparazioni tra due espressioni che condividono un tipo comune. Restituisce Bool.
  • | & ^ : esegue operazioni binarie tra due espressioni Int. Restituisce Int.
  • << >> >>> : esegue shift binari tra due espressioni Int. Restituisce Int.
  • e1 + e2 : esegue l'addizione o concatena stringhe. Restituisce Int se entrambe le espressioni sono Int, Float se almeno una è di tipo Float altrimenti se entrambe sono stringhe concatena e restituisce una String.
  • e1 - e2 : esegue la sottrazione tra due espressioni Int o Float. Restituisce Int se entrambe sono Int e restituisce Float se almeno una è di tipo Float'.
  • e1 * e2 : moltiplica due numeri, restituisce lo stesso tipo della sottrazione.
  • e1 / e2 : divide due numeri, restituisce Float.
  • e1 % e2 : modulo di due numeri, restituisce lo stesso tipo della sottrazione.

Operazioni Unarie

Le seguenti operazioni unarie sono disponibili:

  • ! : il not booleano. Inverte il valore Bool dell'espressione.
  • - : numero negativo, cambia il segno del valore di un Int o di un Float.
  • ++ e -- possono essere usati prima o dopo di una espressione. Quando usati prima, prima incrementano la variabile corrispondente e poi restituiscono il valore incrementato. Quando usati dopo, incrementano la variabile ma restituiscono il valore che aveva prima. Possono essere usati solo con valori Int o Float.
  • ~ : complemento ad uno di un Int.

Nota: ~ è usato solitamente per interi a 32-bit, quindi non restituisce il risultato
atteso con gli interi a 31 bit di Neko, questo è perché non funziona su Neko.

Parentesi

Le espressioni possono essere delimitate con parentesi in modo da dare una specifica priorità quando si eseguono operazioni. Il tipo di ( e ) è lo stesso di e ed entrambi restituiscono lo stesso valore.

Blocchi

I blocchi possono eseguire diverse espressioni. La sintassi di un blocco è la seguente:

{
    e1;
    e2;
        // ...
    eX;
}

Un blocco restituisce il tipo e valore dell'ultima espressione del blocco. Ad esempio:

{ f(); x = 124; true; }

Questo blocco è di tipo Bool e viene valutato true.

Per convenzione il blocco vuoto { } viene valutato Void.

Variabili Locali

Le variabili locali possono essere dichiarate in blocchi usando var, come mostra l'esempio seguente:

{
    var x;
    var y = 3;
    var z : String;
    var w : String = "";
    var a, b : Bool, c : Int = 0;
}

Una variabile può essere dichiarata con un tipo opzionale ed un opzionale valore iniziale. Se nessun valore è dato allora la variabile vale null di default. Se nessun tipo è dato, allora il tipo della variabile è Unknown (sconosciuto) ma sarebbe ancora strettamente tipizzato. Questo verrà spiegato in dettaglio quando introdurremo l'inferenza dei tipi.

Diverse variabili locali possono essere dichiarate con lo stesso var.

Le variabili locali sono definite soltanto fino a quando il blocco che le ha dichiarate chiude. Non è possibile accedervi fuori dal blocco in cui sono state dichiarate.

Identificatori

Quando un identificatore di una variabile viene trovato, è risolto usando il seguente ordine:

  • variabili locali, ha priorità l'ultima dichiarata
  • membri delle classi (classe corrente e campi ereditati)
  • campi statici della classe corrente
  • costruttori enum che sono stati dichiarati in questo file o importati
    enum Asse {
        x;
        y;
        z;
    }

    class C {
        static var x : Int;
        var x : Int;

        function new() {
            {
               // x in questo punto identifica la variabile membro this.x
                var x : String;
                // x in questo punto identifica la variabile locale
            }
        }

        function f(x : String) {
            // x in questo punto identifica il parametro della funzione
        }

        static function f() {
            // x in questo punto identifica la variabile statica della classe
        }
    }

    class D {
        function new() {
            // x qui indica il costruttore x di Asse
        }
    }

Gli identificatori di tipo sono risolti in accordo ai package importati, come spiegheremo più avanti.

Accesso ai Campi

L'accesso ai campi di un oggetto è fatta usando la tradizionale notazione punto:

    o.campo

Chiamate

Puoi chiamare funzioni usando parentesi e virgole per delimitare gli argomenti. Puoi chiamare i metodi usando la notazione punto sull'oggetto:

    f(1,2,3);
    oggetto.metodo(1,2,3);

New

La parola chiave new è usata nelle espressioni per creare una nuova istanza di una classe. Necessita di un nome di classe e può prendere parametri:

    a = new Array();
    s = new String("hello");

Array

Puoi creare array direttamente da una lista di valori usando la sintassi seguente:

    var a : Array<Int> = [1,2,3,4];

Nota che quel tipo di array prende un parametro di tipo che è il tipo degli oggetti conservati nell'Array. In questo modo tutte le operazioni sull'array sono sicure. Come conseguenza, tutti gli oggetti in un dato Array devono essere dello stesso tipo.

Puoi leggere e scrivere dentro un Array usando le tradizionali parentesi quadre:

    primo = a[0];
    a[1] = valore;

L'indice dell'array deve essere di tipo Int.

If

Qui ci sono alcuni esempi di espressioni con if:

    if (life == 0) destroy();
    if (flag) 1 else 2;

Qui la generica sintassi delle espressioni if:

    if( espr-cond ) espr-1 [else espr-2]

Prima è valutata espr-cond'. Deve essere di tipo Bool. Quindi se true allora viene valutata espr-1, altrimenti, se c'è una espr-2' allora questa viene valutata.

Se non c'è alcun else e la condizione del blocco if è falsa, allora l'intera espressione ha tipo Void. Se c'è un else allora espr-1 ed espr-2 devono essere dello stesso tipo e questo sarà il tipo dell'espressione if:

    var x : Void = if( flag ) destroy();
    var y : Int = if( flag ) 1 else 2;

In Haxe, if è simile alla sintassi del C dell'operatore ternario a?b:c.

Per convenzione se un blocco if non è supposto di restituire alcun valore (se non lo vogliamo assegnare ad alcuna variabile) allora espr-1 ed espr-2 possono avere tipi differenti ed il tipo del blocco if sarà Void.

While

I While sono cicli standard che usano una pre-condizione o una post-condizione:

    while( espr-cond ) espr-loop;
    do espr-loop while( espr-cond );

Per esempio:

    var i = 0;
    while( i < 10 ) {
        // ...
        i++;
    }

O usando do...while:

    var i = 0;
    do {
        // ...
        i++;
    } while( i < 10 );

Come con if, expr-cond in un ciclo while deve essere di tipo Bool.

Un altro utile esempio che produce un ciclo per contare da 10 a 1:

    var i = 10;
    while( i > 0 ) {
    .......
    i--;
    }

For

I cicli for sono un po' differenti dai tradizionali cicli for del C. Essi sono attualmente usati con gli iteratori, che saranno introdotti più tardi in questa guida. Ecco un esempio di un ciclo for:

    for( i in 0...a.length ) {
        foo(a[i]);
    }

Return

Per uscire da una funzione prima della fine o restituire un valore da una funzione, puoi usare l'espressione return:

    function dispari( x : Int ) : Bool {
        if( x % 2 != 0 )
            return true;
        return false;
    }

L'espressione return può essere usata senza argomenti se la funzione non richiede un valore da restituire:

    function tizio() : Void {
        // ...
        if( abort )
            return;
        // ....
    }

Break e Continue

Queste due parole chiavi sono utili per uscire prima da un ciclo for o while o per andare alla prossima iterazione di un ciclo:

    var i = 0;
    while( i < 10 ) {
        if( i == 7 )
            continue; // salta questa iterazione.
            // non esegue nessun'altra istruzione in questo blocco,
            // MA torna a valutare la condizione del ''while''.
        if( flag )
            break; // ferma prima.
            // Salta fuori del ciclo ##TAG0##, e continua l'esecuzione 
            // con le istruzioni che seguono il ciclo while.
    }

Eccezioni

Le eccezioni sono un modo di fare un salto non locale. Puoi lanciare (throw) una eccezione e prenderla (catch) da qualsiasi funzione chiamata sullo stack:

    function caio() {
        // ...
        throw new Error("caio invalido");
    }

    // ...

    try {
        caio();
    } catch( e : Error ) {
        //gestisce l'eccezione
    }

Possono esserci diversi blocchi catch dopo un try, in modo da prendere diversi tipi di eccezione. Vengono testati nell'ordine in cui sono dichiarati. Catturando Dynamic cattureremo tutte le eccezioni:

    try {
        foo();
    } catch( e : String ) {
        // gestisce questo tipo di errore 
    } catch( e : Error ) {
        // gestisce un altro tipo di errore
    } catch( e : Dynamic ) {
        // gestisce tutti gli altri errori
    }

Tutte le espressioni try e catch devono restituire valori dello stesso tipo eccetto quando nessun valore è richiesto (come if).

Switch

Gli switch sono un modo di esprimere molteplici casi if...else if... else if sullo stesso valore:

    if( v == 0 )
        e1
    else if( v == sempronio(1) )
        e2
    else if( v == 65 )
        e3
    else
        e4;

Sarebbe tradotto nel seguente switch:

    switch( v ) {
    case 0:
        e1;
    case sempronio(1):
        e2;
    case 65:
        e3;
    default:
        e4;
    }

Gli switch in Haxe sono differenti dagli switch tradizionali : tutti i casi sono espressioni separate così dopo che è eseguita una espressione di un caso, lo switch esce automaticamente. Di conseguenza break non può essere usato in uno switch e la posizione di default non è importante.

Su alcune piattaforme, gli switch su valori costanti (specialmente costanti intere) potrebbero essere ottimizzati per maggiore velocità.

Gli switch possono anche essere usati sugli enum con una semantica differente. Sarà spiegato più in là in questa guida.

Funzioni Locali

Le funzioni locali sono dichiarate usando la parola chiave function ma non possono avere un nome. Hanno un valore proprio come gli interi o le stringhe:

    var f = function() { /* ... */ };
    f(); // chiama la funzione

Le funzioni locali possono accedere ai loro parametri, alle variabili locali che sono state dichiarate prima e alle variabili statiche della classe corrente:

    var x = 10;
    var add = function(n) { x += n; };
    add(2);
    add(3);
    // ora x è 15

Tuttavia, le funzioni locali dichiarate nei metodi non possono accedere al valore this. Hai bisogno di dichiarare una variabile come me:

    class C {

        var x : Int;

        function f() {
            // NON COMPILA
            var add = function(n) { this.x += n; };
        }

        function f2() {
            // compila
            var me = this;
            var add = function(n) { me.x += n; };
        }
    }

Oggetti Anonimi

Gli Oggetti Anonimi possono essere dichiarati usando la seguente sintassi:

    var o = { age : 26, name : "Tom" };

Nota che a causa della inferenza dei tipi, anche gli oggetti anonimi sono strettamente tipizzati.

«« Tipi Base - Type Inference »»

version #4181, modified 2008-09-06 17:24:21 by Kris