5. Variabili
5.1 Dichiarazione di variabili
In MALDA le variabili si dichiarano con la keyword var, seguita dal nome e da un valore iniziale opzionale:
var x = 10;
var name = "Alice";
var isActive = true;
var pi = 3.14159;
Le variabili vanno dichiarate prima dell'uso. Il tipo viene inferito dal valore iniziale. Per i binding che non devono mai essere riassegnati, usa const al posto di var (vedi 5.3 Dichiarazioni di costanti).
Dopo il nome puoi aggiungere un type hint informativo. A interpret-time gli hint sono documentazione per te e per l'IDE, non controlli runtime:
var name: Type? = value;
Esempio: var count: int = 0;, var msg: string = "hello";, oppure var p: Person = new Person();
--strict-types trasforma i disallineamenti degli hint in Error di analisi. malda compile --mode transpile e publish rifiutano l'emit quando l'analisi riporta Error; --lenient-types salta quel gate. I nomi di hint noti includono i primitivi Tier 0 (int, string, …), i nomi di class/schema/sum-type dichiarati (stessa unit o moduli importati) e le classi host built-in (per esempio RestServer). Il language server emette un Error di default quando un hint non coincide con un letterale, un'espressione new ClassName(), un altro identificatore che porta un hint noto, o un risultato di chiamata il cui callee dichiara un hint di ritorno (per esempio var n: int = "abc";, var p: Person = 1;, n = s; quando s: string, oppure var n: int = make(); quando make() -> string). Lo stesso controllo copre assegnamenti, argomenti di chiamata e valori di return rispetto agli hint di parametro/->. Gli operatori e i tipi di ritorno dei built-in non vengono inferiti.
5.2 Assegnamento di variabili
Dopo la dichiarazione, le variabili si possono riassegnare con l'operatore di assegnamento =:
x = 20;
name = "Bob";
x = x + 1;
5.3 Dichiarazioni di costanti
Un binding dichiarato con const invece di var non può essere riassegnato. L'inizializzatore è obbligatorio:
const MAX_RETRIES = 3;
const APP_NAME = "malda-demo";
print(MAX_RETRIES); // 3
Tentare di assegnare a una costante è un errore a runtime che nomina il binding:
const limit = 10;
limit = 20; // Runtime error: Cannot assign to const 'limit'.
Anche l'assegnamento composto (+=) e gli operatori di incremento sono assegnamenti, quindi su una costante falliscono per lo stesso motivo.
Le costanti sono shallow
const congela il binding, non il valore a cui punta. Una costante che contiene un array, un dizionario o un oggetto consente comunque di modificare i contenuti:
const config = dict { "retries": 3 };
config["retries"] = 5; // Allowed: the dictionary is mutated, not the binding
print(config["retries"]); // 5
// config = dict { }; // Runtime error: Cannot assign to const 'config'.
Scope e shadowing
Le costanti seguono lo stesso scope di blocco di var, e uno scope interno può fare shadowing di una costante esterna con un proprio binding:
const mode = "prod";
function describe() {
var mode = "local"; // Shadows the outer constant inside this function
return mode;
}
print(describe()); // "local"
print(mode); // "prod"
const per valori di configurazione, limiti e tabelle di lookup che non devono cambiare durante una run. Tutto il resto resta var; MALDA non obbliga a usare le costanti e non le ottimizza in modo diverso.
5.4 Destrutturazione
La destrutturazione permette di estrarre valori da array e oggetti in variabili distinte, in una sola istruzione.
Destrutturazione di array
Estrai gli elementi di un array in variabili:
var arr = [10, 20];
var [x, y] = arr;
print(x); // Prints: 10
print(y); // Prints: 20
Pattern rest: usa ...rest per catturare gli elementi rimanenti:
var arr = [1, 2, 3, 4, 5];
var [first, second, ...rest] = arr;
// first = 1, second = 2, rest = [3, 4, 5]
print(length(rest)); // Prints: 3
Note:
- L'array deve avere almeno tanti elementi quante sono le variabili (a meno che non usi il pattern rest)
- Il pattern rest deve stare in ultima posizione
- Puoi saltare elementi con il pattern wildcard
_
Destrutturazione di oggetti
Estrai le proprietà di un oggetto in variabili:
var user = { name: "Alice", age: 30, role: "admin" };
var { name, age } = user;
print(name); // Prints: "Alice"
print(age); // Prints: 30
Rinomina: estrai le proprietà con nomi di variabile diversi:
var user = { name: "Bob", age: 25 };
var { name: userName, age: userAge } = user;
print(userName); // Prints: "Bob"
print(userAge); // Prints: 25
Destrutturazione nidificata: estrai da oggetti nidificati:
var data = {
user: { name: "Charlie", age: 35 },
role: "admin"
};
var { user: { name, age }, role } = data;
print(name); // Prints: "Charlie"
print(age); // Prints: 35
print(role); // Prints: "admin"
Assegnamento con destrutturazione
Puoi usare la destrutturazione anche in assegnamento (su variabili già esistenti):
var x = 0;
var y = 0;
var arr = [10, 20];
[x, y] = arr; // Assigns 10 to x, 20 to y
print(x + y); // Prints: 30
var name = "";
var age = 0;
var user = { name: "David", age: 40 };
{ name, age } = user; // Assigns properties to variables
print(name); // Prints: "David"
print(age); // Prints: 40
Destrutturazione del valore di ritorno di una funzione
Destruttura i valori restituiti dalle funzioni:
function getPoint() {
return { x: 5, y: 10 };
}
var { x, y } = getPoint();
print(x + y); // Prints: 15
Gestione degli errori
Se un pattern di destrutturazione non corrisponde (per esempio array troppo corto, proprietà dell'oggetto mancante), viene lanciato un errore a runtime:
try {
var arr = [1, 2];
var [x, y, z] = arr; // Error: array has only 2 elements
} catch (e) {
print("Destructuring failed: " + e);
}
- Usa la destrutturazione per rendere il codice più leggibile quando lavori con dati strutturati
- È particolarmente utile quando elabori risposte API o valori di ritorno di funzioni
- Puoi combinare destrutturazione di array e di oggetti in strutture nidificate
- Usa il pattern rest per catturare gli elementi rimanenti quando non conosci la lunghezza esatta
5.5 Scope delle variabili
In MALDA le variabili hanno block scope. Una variabile è accessibile nel blocco in cui è dichiarata e in tutti i blocchi nidificati.
Variabili globali
Le variabili dichiarate fuori dalle funzioni sono globali e accessibili in tutto il programma:
var globalVar = 10;
function test() {
print(globalVar); // Can access global variable
}
test();
Variabili locali
Le variabili dichiarate dentro una funzione sono locali a quella funzione:
function test() {
var localVar = 20;
print(localVar); // Can access local variable
}
// print(localVar); // Error: localVar is not accessible here
Shadowing delle variabili
Le variabili locali fanno shadowing delle variabili globali con lo stesso nome:
var x = 10; // Global variable
function test() {
var x = 20; // Local variable shadows global x
print(x); // Prints 20 (local)
}
test();
print(x); // Prints 10 (global)
Scope di blocco
Le variabili dichiarate nei blocchi (if, while, for) hanno scope limitato a quel blocco:
if (true) {
var blockVar = 30;
print(blockVar); // Can access blockVar
}
// print(blockVar); // Error: blockVar is not accessible here
Vedi anche
- 4. Tipi di dati - Tipi che le variabili possono contenere
- 8. Strutture di controllo - Pattern matching e block scoping
- 6. Array - Array usati nella destrutturazione
- 9. Funzioni - Scope delle funzioni e parametri