[{"data":1,"prerenderedAt":27},["ShallowReactive",2],{"articolo-pattern-e-records-in-dart-3-pattern-matching-e-destructuring-in-flutter":3,"comments-article-pattern-e-records-in-dart-3-pattern-matching-e-destructuring-in-flutter":26},{"id":4,"title":5,"slug":6,"excerpt":7,"body":8,"cover_image":9,"cover_remote_url":10,"cover_credit":11,"video_url":15,"status":16,"published_at":17,"meta_title":18,"meta_description":19,"category":20,"author":24},67,"Pattern e records in Dart 3: pattern matching e destructuring in Flutter","pattern-e-records-in-dart-3-pattern-matching-e-destructuring-in-flutter","Dart 3 ha introdotto pattern matching, records e destructuring: scopri come questi strumenti rendono il codice Flutter più conciso, leggibile e sicuro.","## Introduzione\n\nCon Dart 3 il linguaggio alla base di Flutter ha compiuto un salto qualitativo enorme grazie all'introduzione dei **records**, del **pattern matching** e del **destructuring**. Si tratta di funzionalità che molti sviluppatori conoscono da altri linguaggi (Kotlin, Rust, Swift) e che finalmente permettono di scrivere codice Flutter più espressivo, riducendo boilerplate e migliorando la sicurezza a compile-time.\n\nIn questo articolo vediamo come usarli concretamente nelle nostre app.\n\n## I Records: tuple leggere e tipizzate\n\nUn **record** è un tipo anonimo che aggrega più valori senza doverne dichiarare una classe. È immutabile e definito al volo.\n\n```dart\n\u002F\u002F Record posizionale\n(int, String) utente = (1, 'Anna');\n\n\u002F\u002F Record con campi nominati\n({double lat, double lng}) posizione = (lat: 45.46, lng: 9.19);\n\nprint(utente.$1);      \u002F\u002F 1\nprint(utente.$2);      \u002F\u002F Anna\nprint(posizione.lat);  \u002F\u002F 45.46\n```\n\nIl caso d'uso più utile è restituire **più valori** da una funzione senza creare una classe dedicata:\n\n```dart\n(String nome, int eta) parseUtente(Map\u003CString, dynamic> json) {\n  return (json['nome'] as String, json['eta'] as int);\n}\n\nfinal (nome, eta) = parseUtente(dati);\nprint('$nome ha $eta anni');\n```\n\n## Destructuring: scomporre i dati\n\nIl **destructuring** consente di estrarre i valori da record, liste e mappe assegnandoli direttamente a variabili.\n\n```dart\n\u002F\u002F Destructuring di una lista\nfinal [primo, secondo, ...resto] = [1, 2, 3, 4, 5];\nprint(primo);  \u002F\u002F 1\nprint(resto);  \u002F\u002F [3, 4, 5]\n\n\u002F\u002F Destructuring di una mappa\nfinal {'nome': nome, 'citta': citta} = {\n  'nome': 'Luca',\n  'citta': 'Roma',\n};\n```\n\nÈ possibile scambiare due variabili senza variabile temporanea:\n\n```dart\nvar a = 1;\nvar b = 2;\n(a, b) = (b, a);\n```\n\n## Pattern matching con switch\n\nIl `switch` in Dart 3 diventa un'espressione potentissima grazie ai pattern. Non serve più il `break` e può restituire un valore.\n\n```dart\nString descriviStato(int codice) {\n  return switch (codice) {\n    200 => 'OK',\n    404 => 'Non trovato',\n    >= 500 => 'Errore server',\n    _ => 'Sconosciuto',\n  };\n}\n```\n\nPossiamo usare pattern anche su record, ideale per gestire coordinate o coppie di valori:\n\n```dart\nString quadrante((int, int) punto) {\n  return switch (punto) {\n    (0, 0) => 'Origine',\n    (var x, var y) when x > 0 && y > 0 => 'Primo quadrante',\n    (var x, _) when x \u003C 0 => 'A sinistra',\n    _ => 'Altrove',\n  };\n}\n```\n\nLa clausola `when` aggiunge condizioni (guard clauses) ai pattern.\n\n## Applicazione pratica in Flutter: gestione degli stati\n\nUn caso reale è la gestione degli stati asincroni. Combinando pattern matching e sealed class otteniamo un codice espressivo e sicuro:\n\n```dart\nsealed class RisultatoUtente {}\nclass Caricamento extends RisultatoUtente {}\nclass Successo extends RisultatoUtente {\n  final String nome;\n  Successo(this.nome);\n}\nclass Errore extends RisultatoUtente {\n  final String messaggio;\n  Errore(this.messaggio);\n}\n\nWidget build(BuildContext context) {\n  final RisultatoUtente stato = _stato;\n  return switch (stato) {\n    Caricamento() => const CircularProgressIndicator(),\n    Successo(nome: final n) => Text('Benvenuto $n'),\n    Errore(messaggio: final m) => Text('Errore: $m'),\n  };\n}\n```\n\nGrazie a `sealed`, il compilatore verifica che **tutti** i casi siano gestiti: se aggiungi un nuovo stato senza gestirlo, ottieni un errore a compile-time. Questo elimina un'intera categoria di bug.\n\n## Object patterns e AsyncSnapshot\n\nI pattern funzionano bene anche con classi esistenti come `AsyncSnapshot` dentro un `FutureBuilder`:\n\n```dart\nFutureBuilder\u003CString>(\n  future: _caricaDati(),\n  builder: (context, snapshot) {\n    return switch (snapshot) {\n      AsyncSnapshot(hasError: true, :final error) =>\n        Text('Errore: $error'),\n      AsyncSnapshot(hasData: true, :final data) =>\n        Text('Dati: $data'),\n      _ => const CircularProgressIndicator(),\n    };\n  },\n)\n```\n\nLa sintassi `:final data` è uno shorthand per `data: final data`.\n\n## If-case: pattern nelle condizioni\n\nOltre allo switch, i pattern si usano anche con `if-case`:\n\n```dart\nfinal json = {'lat': 45.46, 'lng': 9.19};\n\nif (json case {'lat': final double lat, 'lng': final double lng}) {\n  print('Coordinate valide: $lat, $lng');\n}\n```\n\nQuesto è particolarmente utile per validare in modo sicuro i dati provenienti da API JSON, controllando struttura e tipi in un colpo solo.\n\n## Conclusioni\n\nRecords, pattern matching e destructuring rappresentano una delle evoluzioni più importanti di Dart. Portano vantaggi concreti:\n\n- **Meno boilerplate**: niente classi per restituire più valori.\n- **Codice più leggibile**: gli switch espressione sono compatti e chiari.\n- **Maggiore sicurezza**: con le sealed class il compilatore garantisce l'esaustività.\n- **Validazione dei dati**: `if-case` semplifica il parsing sicuro del JSON.\n\nAdottare queste funzionalità nei progetti Flutter moderni significa scrivere codice più robusto e manutenibile. Vale la pena rifattorizzare gli switch tradizionali e le funzioni con parametri di output per sfruttarne appieno il potenziale.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Farticles\u002F5ea82b44-732b-490e-970b-5c08a7c81d0b.jpg","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1635772429032-26a9edb43ba2?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w5NzA2NTJ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3ODczMTU4NTV8&ixlib=rb-4.1.0&q=80&w=1080",{"name":12,"author_url":13,"photo_url":14},"Pierre Bamin","https:\u002F\u002Funsplash.com\u002F@bamin","https:\u002F\u002Funsplash.com\u002Fphotos\u002Fa-close-up-view-of-a-puzzle-piece-Lmh_-gFu8vU",null,"published","2026-08-15T04:00:40+00:00","Pattern matching e records in Dart 3 per Flutter","Guida pratica a records, pattern matching e destructuring in Dart 3: scrivi codice Flutter più conciso, leggibile e sicuro con esempi reali.",{"id":21,"name":22,"slug":23},1,"Guide","guide",{"id":21,"name":25},"Flutter Bot",[],1789120587618]