[{"data":1,"prerenderedAt":85},["ShallowReactive",2],{"tutorial-dart-essenziale-per-flutter-variabili-funzioni-classi-async-e-await":3,"comments-tutorial-dart-essenziale-per-flutter-variabili-funzioni-classi-async-e-await":84},{"id":4,"title":5,"slug":6,"excerpt":7,"intro":8,"cover_image":9,"cover_remote_url":10,"cover_credit":11,"video_url":15,"video":16,"difficulty":20,"estimated_minutes":21,"flutter_version":22,"status":23,"published_at":24,"meta_title":25,"meta_description":26,"category":27,"author":31,"steps":33},71,"Dart essenziale per Flutter: variabili, funzioni, classi, async e await","dart-essenziale-per-flutter-variabili-funzioni-classi-async-e-await","Prima di scrivere widget serve conoscere Dart. In questa guida impari variabili, null safety, funzioni, classi e programmazione asincrona con Future, async e await, con esempi eseguibili subito.","Molti principianti aprono il primo progetto Flutter e si trovano davanti a righe come `final List\u003CString> items = [];` oppure `Future\u003Cvoid> load() async { ... }` senza sapere davvero cosa stiano leggendo. Flutter è scritto in **Dart**, e conoscere le basi del linguaggio è la differenza tra copiare codice e capirlo.\n\nIn questo tutorial ripercorriamo il minimo indispensabile di Dart per lavorare bene con Flutter:\n\n- variabili, tipi e **null safety**\n- funzioni, parametri opzionali e nominati, arrow function\n- collezioni (`List`, `Map`) e cicli\n- classi, costruttori, `final`, getter ed ereditarietà\n- programmazione **asincrona** con `Future`, `async`\u002F`await` e gestione degli errori\n\nOgni esempio è eseguibile in un file Dart puro (anche su [dartpad.dev](https:\u002F\u002Fdartpad.dev), senza installare nulla) e nell'ultimo passo vedremo come questi concetti si traducono in un widget Flutter reale.\n\n> **Prerequisiti:** nessuno, se usi DartPad. Se preferisci l'IDE, ti basta avere l'SDK Flutter installato.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Ftutorials\u002Fa1e2016a-7784-4bcc-917a-16c061136894.jpg","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1484665739383-a1069a82d4be?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w5NzA2NTJ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3ODczNzMwOTJ8&ixlib=rb-4.1.0&q=80&w=1080",{"name":12,"author_url":13,"photo_url":14},"Ehud Neuhaus","https:\u002F\u002Funsplash.com\u002F@paramir","https:\u002F\u002Funsplash.com\u002Fphotos\u002Fbook-beside-laptop-computer-esCc1qx6TVw","https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=IrKupbOmGYM",{"youtube_id":17,"duration_seconds":18,"published_at":19},"IrKupbOmGYM",144,"2026-08-22T05:11:45+00:00","beginner",35,"3.x (Dart 3.x)","published","2026-08-22T04:31:33+00:00","Dart essenziale per Flutter: guida base per iniziare","Impara le basi di Dart per Flutter: variabili, null safety, funzioni, classi, Future, async e await con esempi pratici pronti da provare su DartPad.",{"id":28,"name":29,"slug":30},1,"Guide","guide",{"id":28,"name":32},"Flutter Bot",[34,42,49,56,63,70,77],{"id":35,"position":28,"title":36,"body":37,"code_snippet":38,"code_language":39,"expected_result":40,"demo_url":41,"video_url":41},472,"Preparare l'ambiente: il primo file Dart","Per esercitarti non serve un progetto Flutter completo. Hai due strade:\n\n1. **DartPad** (consigliato per iniziare): vai su [dartpad.dev](https:\u002F\u002Fdartpad.dev), cancella il codice di esempio e incolla il tuo.\n2. **Locale**: crea un file `bin\u002Fmain.dart` in una cartella qualsiasi e lancialo con `dart run bin\u002Fmain.dart` (l'SDK Dart è incluso in Flutter).\n\nOgni programma Dart parte dalla funzione `main()`. Per stampare a console si usa `print()`.\n\nNota: in Flutter la `main()` esiste sempre ed è quella che chiama `runApp()`. È lo stesso identico punto di ingresso che vedi qui.","void main() {\n  print('Ciao Dart!');\n\n  \u002F\u002F I commenti su una riga iniziano con \u002F\u002F\n  \u002F* oppure si usano i commenti\n     su più righe come questo *\u002F\n\n  final anno = 2024;\n  print('Siamo nel $anno'); \u002F\u002F string interpolation\n  print('Fra 2 anni: ${anno + 2}'); \u002F\u002F espressione dentro ${}\n}","dart","In console vedi: \"Ciao Dart!\", \"Siamo nel 2024\", \"Fra 2 anni: 2026\". Hai imparato anche la string interpolation con $ e ${}.",null,{"id":43,"position":44,"title":45,"body":46,"code_snippet":47,"code_language":39,"expected_result":48,"demo_url":41,"video_url":41},473,2,"Variabili, tipi e null safety","Dart è **tipizzato staticamente**, ma può inferire il tipo. Le parole chiave da conoscere sono tre:\n\n- `var`: il tipo viene dedotto dal valore iniziale, ma la variabile resta riassegnabile.\n- `final`: assegnata una sola volta, a runtime. **È quella che userai più spesso in Flutter.**\n- `const`: costante nota già in fase di compilazione (in Flutter serve anche a ottimizzare i widget).\n\n### Null safety\nDal Dart 2.12 una variabile **non può contenere `null`** a meno che tu non lo dichiari esplicitamente aggiungendo `?` al tipo. Questo elimina alla radice il classico crash \"null reference\".\n\nOperatori utili:\n\n| Operatore | Significato |\n|---|---|\n| `?` | il tipo può essere null (`String? nome`) |\n| `??` | valore di fallback se null (`nome ?? 'Anonimo'`) |\n| `?.` | accesso sicuro (`nome?.length`) |\n| `!` | \"so che non è null\" — usalo con cautela |\n| `late` | inizializzo dopo, ma prima dell'uso |","void main() {\n  var citta = 'Roma';      \u002F\u002F String inferita\n  citta = 'Milano';        \u002F\u002F ok: var è riassegnabile\n\n  final utente = 'Anna';   \u002F\u002F non riassegnabile\n  const pi = 3.14;         \u002F\u002F costante a compile-time\n\n  int eta = 30;\n  double altezza = 1.75;\n  bool attivo = true;\n\n  \u002F\u002F Null safety\n  String? soprannome;             \u002F\u002F può essere null\n  print(soprannome);              \u002F\u002F null\n  print(soprannome ?? 'nessuno'); \u002F\u002F nessuno\n  print(soprannome?.length);      \u002F\u002F null, niente crash\n\n  soprannome = 'Anni';\n  print(soprannome.toUpperCase()); \u002F\u002F ANNI\n\n  \u002F\u002F late: prometto di assegnarla prima dell'uso\n  late String messaggio;\n  messaggio = 'Benvenuta $utente';\n\n  print('$messaggio ($eta anni, $altezza m, attivo: $attivo, pi=$pi, $citta)');\n}","La console stampa null, \"nessuno\", null, \"ANNI\" e la frase finale. Se provi a scrivere `String x = null;` l'editor segnala subito un errore di compilazione: è la null safety al lavoro.",{"id":50,"position":51,"title":52,"body":53,"code_snippet":54,"code_language":39,"expected_result":55,"demo_url":41,"video_url":41},474,3,"Funzioni: parametri posizionali, opzionali e nominati","Una funzione in Dart dichiara il tipo di ritorno (`void` se non restituisce nulla) e i parametri.\n\nEsistono tre modi di passare i parametri:\n\n- **posizionali obbligatori**: `saluta(String nome)`\n- **posizionali opzionali**: tra parentesi quadre `[int? volte]`\n- **nominati**: tra graffe `{required String nome, int volte = 1}`\n\nI parametri **nominati** sono quelli che vedi ovunque in Flutter: `Text('ciao', style: ..., textAlign: ...)`. La parola chiave `required` indica che il parametro nominato è obbligatorio.\n\nSe il corpo è una sola espressione, puoi usare la **arrow syntax** `=>`. Infine, in Dart le funzioni sono valori: puoi passarle come argomento (è ciò che accade con `onPressed: () { ... }`).","\u002F\u002F Parametri posizionali\nint somma(int a, int b) {\n  return a + b;\n}\n\n\u002F\u002F Arrow function (una sola espressione)\nint quadrato(int n) => n * n;\n\n\u002F\u002F Parametri nominati, con default e required\nString descrivi({required String nome, int eta = 0, String? citta}) {\n  final luogo = citta == null ? '' : ' di $citta';\n  return '$nome, $eta anni$luogo';\n}\n\n\u002F\u002F Funzione che riceve un'altra funzione (callback)\nvoid ripeti(int volte, void Function(int) azione) {\n  for (var i = 1; i \u003C= volte; i++) {\n    azione(i);\n  }\n}\n\nvoid main() {\n  print(somma(3, 4));      \u002F\u002F 7\n  print(quadrato(5));      \u002F\u002F 25\n\n  print(descrivi(nome: 'Luca', eta: 28, citta: 'Torino'));\n  print(descrivi(nome: 'Sara')); \u002F\u002F eta usa il default\n\n  ripeti(3, (i) => print('Giro numero $i'));\n}","Output: 7, 25, \"Luca, 28 anni di Torino\", \"Sara, 0 anni\", poi tre righe \"Giro numero 1\u002F2\u002F3\". Hai visto la stessa sintassi dei callback Flutter come onPressed.",{"id":57,"position":58,"title":59,"body":60,"code_snippet":61,"code_language":39,"expected_result":62,"demo_url":41,"video_url":41},475,4,"Collezioni e cicli: List, Map e i metodi che userai in Flutter","Le due collezioni fondamentali sono:\n\n- `List\u003CT>`: elenco ordinato (in Flutter diventa la lista di dati che mostri in una `ListView`).\n- `Map\u003CK, V>`: coppie chiave\u002Fvalore (tipico risultato del parsing di un JSON).\n\nOltre ai cicli `for` e `for-in`, impara subito i metodi funzionali: `map`, `where`, `firstWhere`, `any`, `reduce`. In Flutter li userai continuamente, ad esempio con `prodotti.map((p) => Text(p.nome)).toList()`.\n\nUtile anche il **collection if** e lo **spread operator** `...`, che in Flutter servono per costruire liste di widget condizionali.","void main() {\n  final linguaggi = \u003CString>['Dart', 'Kotlin', 'Swift'];\n  linguaggi.add('JavaScript');\n\n  for (final l in linguaggi) {\n    print('- $l');\n  }\n\n  \u002F\u002F map \u002F where restituiscono Iterable: spesso serve .toList()\n  final maiuscoli = linguaggi.map((l) => l.toUpperCase()).toList();\n  final corti = linguaggi.where((l) => l.length \u003C= 5).toList();\n  print(maiuscoli);\n  print(corti);\n\n  \u002F\u002F Map chiave\u002Fvalore\n  final utente = \u003CString, dynamic>{\n    'nome': 'Anna',\n    'eta': 30,\n    'admin': false,\n  };\n  print(utente['nome']);\n  utente['citta'] = 'Bologna';\n  print(utente.keys.toList());\n\n  \u002F\u002F Collection if e spread\n  final mostraExtra = true;\n  final menu = \u003CString>[\n    'Home',\n    'Profilo',\n    if (mostraExtra) 'Impostazioni',\n    ...['Aiuto', 'Logout'],\n  ];\n  print(menu);\n}","Vedi la lista dei linguaggi riga per riga, gli array trasformati con map\u002Fwhere, il valore 'Anna' e le chiavi della Map, e infine il menu con 'Impostazioni' incluso perché mostraExtra è true.",{"id":64,"position":65,"title":66,"body":67,"code_snippet":68,"code_language":39,"expected_result":69,"demo_url":41,"video_url":41},476,5,"Classi, costruttori e modelli di dati","Le classi in Dart servono soprattutto a creare i **modelli** della tua app (Utente, Prodotto, Articolo...).\n\nPunti chiave:\n\n- I campi `final` rendono l'oggetto **immutabile**: pratica consigliata in Flutter.\n- Il **costruttore abbreviato** `Prodotto(this.nome, this.prezzo)` assegna direttamente i campi.\n- I **costruttori nominati** (`Prodotto.gratis()`) offrono modi alternativi di creare l'oggetto; molto comune `Prodotto.fromJson(Map)`.\n- I **getter** calcolano un valore al volo.\n- `extends` per l'ereditarietà, `@override` per ridefinire un metodo (come `toString()` o il `build()` dei widget!).\n\nQuando in Flutter scrivi `class HomePage extends StatelessWidget` stai usando esattamente questi meccanismi.","class Prodotto {\n  final String nome;\n  final double prezzo;\n  final int quantita;\n\n  \u002F\u002F Costruttore con parametri nominati\n  const Prodotto({\n    required this.nome,\n    required this.prezzo,\n    this.quantita = 1,\n  });\n\n  \u002F\u002F Costruttore nominato: crea l'oggetto da una Map (tipico JSON)\n  factory Prodotto.fromJson(Map\u003CString, dynamic> json) {\n    return Prodotto(\n      nome: json['nome'] as String,\n      prezzo: (json['prezzo'] as num).toDouble(),\n      quantita: json['quantita'] as int? ?? 1,\n    );\n  }\n\n  \u002F\u002F Getter calcolato\n  double get totale => prezzo * quantita;\n\n  @override\n  String toString() => '$nome x$quantita = ${totale.toStringAsFixed(2)} EUR';\n}\n\nclass ProdottoScontato extends Prodotto {\n  final double sconto; \u002F\u002F 0.2 = 20%\n\n  const ProdottoScontato({\n    required super.nome,\n    required super.prezzo,\n    super.quantita,\n    required this.sconto,\n  });\n\n  @override\n  double get totale => super.totale * (1 - sconto);\n}\n\nvoid main() {\n  final p = Prodotto(nome: 'Tastiera', prezzo: 49.90, quantita: 2);\n  print(p);\n\n  final s = ProdottoScontato(nome: 'Mouse', prezzo: 30, sconto: 0.25);\n  print(s);\n\n  final daJson = Prodotto.fromJson({'nome': 'Monitor', 'prezzo': 199});\n  print(daJson);\n}","Console: \"Tastiera x2 = 99.80 EUR\", \"Mouse x1 = 22.50 EUR\", \"Monitor x1 = 199.00 EUR\". Hai creato un modello immutabile, un costruttore da JSON e una sottoclasse che sovrascrive un getter.",{"id":71,"position":72,"title":73,"body":74,"code_snippet":75,"code_language":39,"expected_result":76,"demo_url":41,"video_url":41},477,6,"Asincronia: Future, async, await e gestione degli errori","Un'app deve leggere dati dalla rete o dal disco senza bloccare l'interfaccia. In Dart le operazioni che finiranno \"più tardi\" restituiscono un **`Future\u003CT>`**: una promessa di valore.\n\nRegole pratiche:\n\n- una funzione che usa `await` deve essere marcata `async`;\n- una funzione `async` restituisce sempre un `Future` (usa `Future\u003Cvoid>` se non ritorna nulla);\n- `await` mette in pausa **solo quella funzione**, non l'intera app;\n- gli errori si gestiscono con `try \u002F catch \u002F finally`;\n- per operazioni indipendenti in parallelo usa `Future.wait([...])`.\n\nEsiste anche lo **`Stream\u003CT>`**: una sequenza di valori nel tempo (es. la posizione GPS), che si consuma con `await for` o `listen`.\n\n**Errore tipico del principiante:** dimenticare `await` e stampare `Instance of 'Future\u003CString>'` invece del valore.","\u002F\u002F Simula una chiamata di rete che impiega 2 secondi\nFuture\u003CString> caricaUtente(int id) async {\n  await Future.delayed(const Duration(seconds: 2));\n  if (id \u003C= 0) {\n    throw Exception('ID non valido: $id');\n  }\n  return 'Utente #$id';\n}\n\nFuture\u003CList\u003CString>> caricaPost() async {\n  await Future.delayed(const Duration(seconds: 1));\n  return ['Primo post', 'Secondo post'];\n}\n\nFuture\u003Cvoid> main() async {\n  print('Inizio caricamento...');\n\n  try {\n    final utente = await caricaUtente(7);\n    print(utente);\n\n    \u002F\u002F Due operazioni in parallelo: dura quanto la più lenta\n    final risultati = await Future.wait([\n      caricaUtente(8),\n      caricaPost(),\n    ]);\n    print(risultati);\n\n    await caricaUtente(-1); \u002F\u002F genera un errore\n  } catch (e) {\n    print('Errore catturato: $e');\n  } finally {\n    print('Operazione terminata');\n  }\n\n  \u002F\u002F Senza await ottieni il Future, non il valore\n  print(caricaUtente(1)); \u002F\u002F Instance of 'Future\u003CString>'\n}","Dopo circa 2 secondi appare \"Utente #7\", poi la lista dei risultati paralleli, quindi \"Errore catturato: Exception: ID non valido: -1\", \"Operazione terminata\" e infine \"Instance of 'Future\u003CString>'\".",{"id":78,"position":79,"title":80,"body":81,"code_snippet":82,"code_language":39,"expected_result":83,"demo_url":41,"video_url":41},478,7,"Mettere tutto insieme in un widget Flutter","Ora colleghiamo i puntini: una piccola app Flutter che usa **una classe modello**, una **funzione asincrona**, una **lista** con `map` e la **null safety**.\n\nCosa riconoscerai:\n\n- `class HomePage extends StatefulWidget` → ereditarietà e `@override`\n- `Future\u003Cvoid> _carica() async` → asincronia\n- `List\u003CProdotto>? _prodotti` → variabile nullable usata come stato \"non ancora caricato\"\n- `_prodotti!.map((p) => ListTile(...)).toList()` → metodi delle collezioni\n- parametri **nominati** ovunque nei costruttori dei widget\n\nCrea un progetto con `flutter create demo_dart`, incolla il codice in `lib\u002Fmain.dart` ed esegui con `flutter run`.","import 'package:flutter\u002Fmaterial.dart';\n\nclass Prodotto {\n  final String nome;\n  final double prezzo;\n  const Prodotto({required this.nome, required this.prezzo});\n}\n\nFuture\u003CList\u003CProdotto>> caricaProdotti() async {\n  await Future.delayed(const Duration(seconds: 2));\n  return const [\n    Prodotto(nome: 'Tastiera', prezzo: 49.90),\n    Prodotto(nome: 'Mouse', prezzo: 29.90),\n    Prodotto(nome: 'Monitor', prezzo: 199.00),\n  ];\n}\n\nvoid main() => runApp(const MyApp());\n\nclass MyApp extends StatelessWidget {\n  const MyApp({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: 'Dart essenziale',\n      theme: ThemeData(colorSchemeSeed: Colors.indigo, useMaterial3: true),\n      home: const HomePage(),\n    );\n  }\n}\n\nclass HomePage extends StatefulWidget {\n  const HomePage({super.key});\n\n  @override\n  State\u003CHomePage> createState() => _HomePageState();\n}\n\nclass _HomePageState extends State\u003CHomePage> {\n  List\u003CProdotto>? _prodotti; \u002F\u002F null = ancora in caricamento\n  String? _errore;\n\n  @override\n  void initState() {\n    super.initState();\n    _carica();\n  }\n\n  Future\u003Cvoid> _carica() async {\n    try {\n      final dati = await caricaProdotti();\n      if (!mounted) return;\n      setState(() => _prodotti = dati);\n    } catch (e) {\n      if (!mounted) return;\n      setState(() => _errore = e.toString());\n    }\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(title: const Text('Catalogo')),\n      body: _errore != null\n          ? Center(child: Text('Errore: $_errore'))\n          : _prodotti == null\n              ? const Center(child: CircularProgressIndicator())\n              : ListView(\n                  children: _prodotti!\n                      .map((p) => ListTile(\n                            leading: const Icon(Icons.shopping_bag),\n                            title: Text(p.nome),\n                            trailing:\n                                Text('${p.prezzo.toStringAsFixed(2)} EUR'),\n                          ))\n                      .toList(),\n                ),\n    );\n  }\n}","All'avvio vedi uno spinner per 2 secondi, poi la lista dei tre prodotti con nome e prezzo. Se in caricaProdotti lanci un'eccezione, compare invece il messaggio di errore.",[],1789205526130]