CINXE.COM
Dive into Dart's patterns and records | Google Codelabs
<!doctype html> <html lang="en" dir="ltr"> <head> <meta name="google-signin-client-id" content="721724668570-nbkv1cfusk7kk4eni4pjvepaus73b13t.apps.googleusercontent.com"> <meta name="google-signin-scope" content="profile email https://www.googleapis.com/auth/developerprofiles https://www.googleapis.com/auth/developerprofiles.award"> <meta property="og:site_name" content="Google Codelabs"> <meta property="og:type" content="website"><meta name="theme-color" content="#1a73e8"><meta charset="utf-8"> <meta content="IE=Edge" http-equiv="X-UA-Compatible"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="manifest" href="/_pwa/codelabs/manifest.json" crossorigin="use-credentials"> <link rel="preconnect" href="//www.gstatic.com" crossorigin> <link rel="preconnect" href="//fonts.gstatic.com" crossorigin> <link rel="preconnect" href="//fonts.googleapis.com" crossorigin> <link rel="preconnect" href="//apis.google.com" crossorigin> <link rel="preconnect" href="//www.google-analytics.com" crossorigin><link rel="stylesheet" href="//fonts.googleapis.com/css?family=Google+Sans:400,500|Roboto:400,400italic,500,500italic,700,700italic|Roboto+Mono:400,500,700&display=swap"> <link rel="stylesheet" href="//fonts.googleapis.com/css2?family=Material+Icons&family=Material+Symbols+Outlined&display=block"><link rel="stylesheet" href="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/codelabs/css/app.css"> <link rel="shortcut icon" href="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/codelabs/images/favicon.png"> <link rel="apple-touch-icon" href="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/codelabs/images/touchicon-180.png"><link rel="canonical" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records"><link rel="search" type="application/opensearchdescription+xml" title="Google Codelabs" href="https://codelabs.developers.google.com/s/opensearch.xml"> <link rel="alternate" hreflang="en" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records" /><link rel="alternate" hreflang="x-default" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records" /><link rel="alternate" hreflang="ar" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records?hl=ar" /><link rel="alternate" hreflang="bn" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records?hl=bn" /><link rel="alternate" hreflang="zh-Hans" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records?hl=zh-cn" /><link rel="alternate" hreflang="zh-Hant" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records?hl=zh-tw" /><link rel="alternate" hreflang="fa" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records?hl=fa" /><link rel="alternate" hreflang="fr" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records?hl=fr" /><link rel="alternate" hreflang="de" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records?hl=de" /><link rel="alternate" hreflang="he" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records?hl=he" /><link rel="alternate" hreflang="hi" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records?hl=hi" /><link rel="alternate" hreflang="id" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records?hl=id" /><link rel="alternate" hreflang="it" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records?hl=it" /><link rel="alternate" hreflang="ja" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records?hl=ja" /><link rel="alternate" hreflang="ko" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records?hl=ko" /><link rel="alternate" hreflang="pl" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records?hl=pl" /><link rel="alternate" hreflang="pt-BR" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records?hl=pt-br" /><link rel="alternate" hreflang="ru" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records?hl=ru" /><link rel="alternate" hreflang="es-419" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records?hl=es-419" /><link rel="alternate" hreflang="th" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records?hl=th" /><link rel="alternate" hreflang="tr" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records?hl=tr" /><link rel="alternate" hreflang="vi" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records?hl=vi" /><title>Dive into Dart's patterns and records | Google Codelabs</title> <meta property="og:title" content="Dive into Dart's patterns and records | Google Codelabs"><meta name="description" content="Use patterns, records, and other new features of Dart 3 to re-architect your UI design style in Flutter."> <meta property="og:description" content="Use patterns, records, and other new features of Dart 3 to re-architect your UI design style in Flutter."><meta property="og:url" content="https://codelabs.developers.google.com/codelabs/dart-patterns-records"><meta property="og:locale" content="en"> <link rel="stylesheet" href="/extras.css"></head> <body class="" template="codelab" theme="codelabs-theme" type="codelab" layout="docs" display-toc pending> <devsite-progress type="indeterminate" id="app-progress"></devsite-progress> <section class="devsite-wrapper"> <devsite-cookie-notification-bar></devsite-cookie-notification-bar><devsite-header role="banner"> <div class="devsite-header--inner nocontent"> <div class="devsite-top-logo-row-wrapper-wrapper"> <div class="devsite-top-logo-row-wrapper"> <div class="devsite-top-logo-row"> <button type="button" id="devsite-hamburger-menu" class="devsite-header-icon-button button-flat material-icons gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Navigation menu button" visually-hidden aria-label="Open menu"> </button> <div class="devsite-product-name-wrapper"> <a href="/" class="devsite-site-logo-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Site logo" track-type="globalNav" track-name="googleCodelabs" track-metadata-position="nav" track-metadata-eventDetail="nav"> <picture> <img src="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/codelabs/images/lockup.svg" class="devsite-site-logo" alt="Google Codelabs"> </picture> </a> </div> <div class="devsite-top-logo-row-middle"> <div class="devsite-header-upper-tabs"> </div> <devsite-search enable-signin enable-search enable-suggestions enable-query-completion tenant-name="Google Codelabs" > <form class="devsite-search-form" action="https://codelabs.developers.google.com/s/results" method="GET"> <div class="devsite-search-container"> <button type="button" search-open class="devsite-search-button devsite-header-icon-button button-flat material-icons" aria-label="Open search"></button> <div class="devsite-searchbox"> <input aria-activedescendant="" aria-autocomplete="list" aria-label="Search" aria-expanded="false" aria-haspopup="listbox" autocomplete="off" class="devsite-search-field devsite-search-query" name="q" placeholder="Search" role="combobox" type="text" value="" > <div class="devsite-search-image material-icons" aria-hidden="true"> </div> <div class="devsite-search-shortcut-icon-container" aria-hidden="true"> <kbd class="devsite-search-shortcut-icon">/</kbd> </div> </div> </div> </form> <button type="button" search-close class="devsite-search-button devsite-header-icon-button button-flat material-icons" aria-label="Close search"></button> </devsite-search> </div> <devsite-language-selector> <ul role="presentation"> <li role="presentation"> <a role="menuitem" lang="en" >English</a> </li> <li role="presentation"> <a role="menuitem" lang="de" >Deutsch</a> </li> <li role="presentation"> <a role="menuitem" lang="es" >Español</a> </li> <li role="presentation"> <a role="menuitem" lang="es_419" >Español – América Latina</a> </li> <li role="presentation"> <a role="menuitem" lang="fr" >Français</a> </li> <li role="presentation"> <a role="menuitem" lang="id" >Indonesia</a> </li> <li role="presentation"> <a role="menuitem" lang="it" >Italiano</a> </li> <li role="presentation"> <a role="menuitem" lang="pl" >Polski</a> </li> <li role="presentation"> <a role="menuitem" lang="pt_br" >Português – Brasil</a> </li> <li role="presentation"> <a role="menuitem" lang="vi" >Tiếng Việt</a> </li> <li role="presentation"> <a role="menuitem" lang="tr" >Türkçe</a> </li> <li role="presentation"> <a role="menuitem" lang="ru" >Русский</a> </li> <li role="presentation"> <a role="menuitem" lang="he" >עברית</a> </li> <li role="presentation"> <a role="menuitem" lang="ar" >العربيّة</a> </li> <li role="presentation"> <a role="menuitem" lang="fa" >فارسی</a> </li> <li role="presentation"> <a role="menuitem" lang="hi" >हिंदी</a> </li> <li role="presentation"> <a role="menuitem" lang="bn" >বাংলা</a> </li> <li role="presentation"> <a role="menuitem" lang="th" >ภาษาไทย</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_cn" >中文 – 简体</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_tw" >中文 – 繁體</a> </li> <li role="presentation"> <a role="menuitem" lang="ja" >日本語</a> </li> <li role="presentation"> <a role="menuitem" lang="ko" >한국어</a> </li> </ul> </devsite-language-selector> <devsite-user enable-profiles fp-auth id="devsite-user"> <span class="button devsite-top-button" aria-hidden="true" visually-hidden>Sign in</span> </devsite-user> </div> </div> </div> </div> </devsite-header> <devsite-book-nav scrollbars hidden> <div class="devsite-book-nav-filter" hidden> <span class="filter-list-icon material-icons" aria-hidden="true"></span> <input type="text" placeholder="Filter" aria-label="Type to filter" role="searchbox"> <span class="filter-clear-button hidden" data-title="Clear filter" aria-label="Clear filter" role="button" tabindex="0"></span> </div> <nav class="devsite-book-nav devsite-nav nocontent" aria-label="Side menu"> <div class="devsite-mobile-header"> <button type="button" id="devsite-close-nav" class="devsite-header-icon-button button-flat material-icons gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Close navigation" aria-label="Close navigation"> </button> <div class="devsite-product-name-wrapper"> <a href="/" class="devsite-site-logo-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Site logo" track-type="globalNav" track-name="googleCodelabs" track-metadata-position="nav" track-metadata-eventDetail="nav"> <picture> <img src="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/codelabs/images/lockup.svg" class="devsite-site-logo" alt="Google Codelabs"> </picture> </a> </div> </div> <div class="devsite-book-nav-wrapper"> <div class="devsite-mobile-nav-top"> <ul class="devsite-nav-list"> </ul> </div> </div> </nav> </devsite-book-nav> <section id="gc-wrapper"> <main role="main" class="devsite-main-content" has-sidebar > <div class="devsite-sidebar"> <div class="devsite-sidebar-content"> <devsite-toc class="devsite-nav" role="navigation" aria-label="On this page" depth="1" scrollbars ></devsite-toc> <devsite-recommendations-sidebar class="nocontent devsite-nav"> </devsite-recommendations-sidebar> </div> </div> <devsite-content> <article class="devsite-article"><style> body { transition: opacity ease-in 0.2s; } body[unresolved] { opacity: 0; display: block; overflow: hidden; position: relative; } </style> <div class="devsite-article-meta nocontent" role="navigation"> <ul class="devsite-breadcrumb-list" > </ul> </div> <h1 class="devsite-page-title" tabindex="-1"> Dive into Dart's patterns and records </h1> <devsite-toc class="devsite-nav" depth="1" devsite-toc-embedded > </devsite-toc> <div class="devsite-article-body clearfix "> <google-codelab-analytics gaid="UA-49880327-14" ga4id="G-JTFZSJVVVZ"></google-codelab-analytics> <google-codelab codelab-gaid="" codelab-ga4id="" doc-id="17L9jk2dhTFrdEqyLb6Wxhq0NeRrtzpQLLJv09qROsA8" id="codelabs/dart-patterns-records" title="Dive into Dart's patterns and records" no-tooltip="" environment="web" category="" feedback-link="https://github.com/flutter/flutter/issues" layout="paginated" > <google-codelab-step label="Introduction" duration="2" step="0"> <google-codelab-about codelab-title="Dive into Dart's patterns and records" authors="John Ryan and Marya Belanger" last-updated="2024-05-12T22:40:22Z" duration="39"> </google-codelab-about> <h2 class="step-title" id="0" data-text="Introduction" tabindex="-1"> 1. Introduction </h2> <p>Dart 3 introduces <em>patterns</em> to the language, a major new category of grammar. Beyond this new way to write Dart code, there are several other language enhancements, including</p> <ul> <li><em>records</em> for bundling data of different types,</li> <li><em>class modifiers</em> for controlling access, and</li> <li>new <em>switch expressions</em> and <em>if-case statements</em>.</li> </ul> <p>These features expand the choices you have when writing Dart code. In this codelab, you learn how to use them to make your code more compact, streamlined, and flexible.</p> <p>This codelab assumes you have some familiarity with Flutter and Dart. If you feel a little rusty, consider brushing up on the basics with the following resources:</p> <ul> <li><a href="https://dart.dev/language" target="_blank">Introduction to Dart</a></li> <li><a href="https://codelabs.developers.google.com/codelabs/flutter-codelab-first" target="_blank">Your first Flutter app</a></li> </ul> <h2 is-upgraded id="what-youll-build" data-text="What you'll build" tabindex="-1">What you'll build</h2> <p>This codelab creates an application that displays a JSON document in Flutter. The application simulates JSON coming from an external source. The JSON contains document data such as the modification date, title, headers, and paragraphs. You write code to neatly pack data into records so that it can be transferred and unpacked wherever your Flutter widgets need it.</p> <p>You then use patterns to build the appropriate widget when the value matches that pattern. You also see how to use patterns to destructure data into local variables.</p> <p class="image-container"><img alt="The final application you build in this codelab, a document with a title, the last modification date, headers and paragraphs." style="width: 624.00px" src="/static/codelabs/dart-patterns-records/img/8bbe85b4fcd936fe.png" srcset="https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/8bbe85b4fcd936fe_36.png 36w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/8bbe85b4fcd936fe_48.png 48w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/8bbe85b4fcd936fe_72.png 72w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/8bbe85b4fcd936fe_96.png 96w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/8bbe85b4fcd936fe_480.png 480w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/8bbe85b4fcd936fe_720.png 720w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/8bbe85b4fcd936fe_856.png 856w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/8bbe85b4fcd936fe_960.png 960w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/8bbe85b4fcd936fe_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/8bbe85b4fcd936fe_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/8bbe85b4fcd936fe_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <h2 class="checklist" is-upgraded id="what-youll-learn" data-text="What you'll learn" tabindex="-1"><strong>What you'll learn</strong></h2> <ul class="checklist"> <li>How to create a record that stores multiple values with different types.</li> <li>How to return multiple values from a function using a record.</li> <li>How to use patterns to match, validate, and destructure data from records and other objects.</li> <li>How to bind pattern-matched values to new or existing variables.</li> <li>How to use new switch statement capabilities, switch expressions, and if-case statements.</li> <li>How to take advantage of <em>exhaustiveness checking</em> to ensure that every case is handled in a switch statement or switch expression.</li> </ul> </google-codelab-step> <google-codelab-step label="Set up your environment" duration="3" step="1"> <h2 class="step-title" id="1" data-text="Set up your environment" tabindex="-1"> 2. Set up your environment </h2> <ol type="1"> <li>Install the <a href="https://docs.flutter.dev/get-started/install" target="_blank">Flutter SDK</a>.</li> <li><a href="https://docs.flutter.dev/get-started/editor" target="_blank">Set up an editor</a> such as Visual Studio Code (VS Code).</li> <li>Go through the <a href="https://docs.flutter.dev/get-started/install/macos#platform-setup" target="_blank">Platform setup</a> steps for at least one target platform (iOS, Android, Desktop, or a web browser).</li> </ol> </google-codelab-step> <google-codelab-step label="Create the project" duration="3" step="2"> <h2 class="step-title" id="2" data-text="Create the project" tabindex="-1"> 3. Create the project </h2> <p>Before diving into patterns, records, and other new features, take a moment to create a simple Flutter project for which you write all your code.</p> <h2 is-upgraded id="create-a-flutter-project" data-text="Create a Flutter project" tabindex="-1">Create a Flutter project</h2> <ol type="1"> <li>Use the <code translate="no" dir="ltr">flutter create</code> command to create a new project named <code translate="no" dir="ltr">patterns_codelab</code>. The <code translate="no" dir="ltr">--empty</code> flag prevents the creation of the standard counter app in the <code translate="no" dir="ltr">lib/main.dart</code> file, which you'd have to remove anyway.</li> </ol> <div></div><devsite-code><pre translate="no" dir="ltr" is-upgraded>flutter create --empty patterns_codelab </pre></devsite-code> <ol type="1" start="2"> <li>Then, open the <code translate="no" dir="ltr">patterns_codelab</code> directory using VS Code.</li> </ol> <div></div><devsite-code><pre translate="no" dir="ltr" is-upgraded>code patterns_codelab </pre></devsite-code> <p class="image-container"><img alt="A screenshot of VS Code displaying the project created with the 'flutter create' command." style="width: 624.00px" src="/static/codelabs/dart-patterns-records/img/3d4047f5db74ac8c.png" srcset="https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/3d4047f5db74ac8c_36.png 36w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/3d4047f5db74ac8c_48.png 48w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/3d4047f5db74ac8c_72.png 72w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/3d4047f5db74ac8c_96.png 96w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/3d4047f5db74ac8c_480.png 480w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/3d4047f5db74ac8c_720.png 720w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/3d4047f5db74ac8c_856.png 856w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/3d4047f5db74ac8c_960.png 960w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/3d4047f5db74ac8c_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/3d4047f5db74ac8c_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/3d4047f5db74ac8c_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <h2 is-upgraded id="set-the-minimum-sdk-version" data-text="Set the minimum SDK version" tabindex="-1"><strong>Set the minimum SDK version</strong></h2> <ul> <li>Set the SDK version constraint for your project to depend on Dart 3 or above.</li> </ul> <h3 is-upgraded id="pubspec.yaml" data-text="pubspec.yaml" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/dart-patterns-and-records/step_03/pubspec.yaml" target="_blank">pubspec.yaml</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="ActionScript 3"><code translate="no" dir="ltr"><span class="devsite-syntax-n">environment</span><span class="devsite-syntax-o">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">sdk</span><span class="devsite-syntax-o">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">^</span><span class="devsite-syntax-mf">3.0</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-mi">0</span> </code></pre></devsite-code> <aside class="special"><p><strong>Did you know?</strong> This is your first introduction to Dart 3! The caret <code translate="no" dir="ltr">^</code> syntax can now be used for SDK constraints (although it has been supported for packages since Dart 1.8). Previously, this would be written <code translate="no" dir="ltr">>=3.0.0 <4.0.0</code>.</p> </aside> </google-codelab-step> <google-codelab-step label="Set up the project" duration="3" step="3"> <h2 class="step-title" id="3" data-text="Set up the project" tabindex="-1"> 4. Set up the project </h2> <p>In this step, you create or update two Dart files:</p> <ul> <li>The <code translate="no" dir="ltr">main.dart</code> file that contains widgets for the app, and</li> <li>The <code translate="no" dir="ltr">data.dart</code> file that provides the app's data.</li> </ul> <p>You will continue modifying both of these files in the subsequent steps.</p> <h2 is-upgraded id="define-the-data-for-the-app" data-text="Define the data for the app" tabindex="-1">Define the data for the app</h2> <ul> <li>Create a new file, <code translate="no" dir="ltr">lib/data.dart</code>, and add the following code to it:</li> </ul> <h3 is-upgraded id="libdata.dart" data-text="lib/data.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/dart-patterns-and-records/step_04/lib/data.dart" target="_blank">lib/data.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Python"><code translate="no" dir="ltr"><span class="devsite-syntax-kn">import</span> <span class="devsite-syntax-s1">'dart:convert'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-k">class</span> <span class="devsite-syntax-nc">Document</span> <span class="devsite-syntax-p">{</span> <span class="devsite-syntax-n">final</span> <span class="devsite-syntax-n">Map<String</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">Object</span><span class="devsite-syntax-err">?</span>> <span class="devsite-syntax-n">_json</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-n">Document</span><span class="devsite-syntax-p">()</span> <span class="devsite-syntax-p">:</span> <span class="devsite-syntax-n">_json</span> <span class="devsite-syntax-o">=</span> <span class="devsite-syntax-n">jsonDecode</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">documentJson</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-n">const</span> <span class="devsite-syntax-n">documentJson</span> <span class="devsite-syntax-o">=</span> <span class="devsite-syntax-s1">'''</span> <span class="devsite-syntax-s1">{</span> <span class="devsite-syntax-s1"> "metadata": {</span> <span class="devsite-syntax-s1"> "title": "My Document",</span> <span class="devsite-syntax-s1"> "modified": "2023-05-10"</span> <span class="devsite-syntax-s1"> },</span> <span class="devsite-syntax-s1"> "blocks": [</span> <span class="devsite-syntax-s1"> {</span> <span class="devsite-syntax-s1"> "type": "h1",</span> <span class="devsite-syntax-s1"> "text": "Chapter 1"</span> <span class="devsite-syntax-s1"> },</span> <span class="devsite-syntax-s1"> {</span> <span class="devsite-syntax-s1"> "type": "p",</span> <span class="devsite-syntax-s1"> "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."</span> <span class="devsite-syntax-s1"> },</span> <span class="devsite-syntax-s1"> {</span> <span class="devsite-syntax-s1"> "type": "checkbox",</span> <span class="devsite-syntax-s1"> "checked": false,</span> <span class="devsite-syntax-s1"> "text": "Learn Dart 3"</span> <span class="devsite-syntax-s1"> }</span> <span class="devsite-syntax-s1"> ]</span> <span class="devsite-syntax-s1">}</span> <span class="devsite-syntax-s1">'''</span><span class="devsite-syntax-p">;</span> </code></pre></devsite-code> <p>Imagine a program receiving data from an external source, like an I/O stream or HTTP request. In this codelab, you simplify that more-realistic use case by mocking incoming JSON data with a multi-line string in the <code translate="no" dir="ltr">documentJson</code> variable.</p> <p>The JSON data is defined in the <code translate="no" dir="ltr">Document</code> class. Later in this codelab, you add functions that return data from the parsed JSON. This class defines and initializes the <code translate="no" dir="ltr">_json</code> field in its constructor.</p> <aside class="special"><p><strong>Did you know?</strong> You can press <code translate="no" dir="ltr">Command</code> or <code translate="no" dir="ltr">Control</code> and click on functions, classes, and libraries in VS Code to see where they are defined.</p> <p>Try doing this on <code translate="no" dir="ltr">jsonDecode</code> and see the editor open to the declaration in the <code translate="no" dir="ltr">dart:convert</code> library.</p> </aside> <h2 is-upgraded id="run-the-app" data-text="Run the app" tabindex="-1">Run the app</h2> <p>The <code translate="no" dir="ltr">flutter create</code> command creates the <code translate="no" dir="ltr">lib/main.dart</code> file as part of the default Flutter file structure.</p> <ol type="1"> <li>To create a starting point for the application, replace the contents of <code translate="no" dir="ltr">main.dart</code> with the following code:</li> </ol> <h3 is-upgraded id="libmain.dart" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/dart-patterns-and-records/step_04/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Python"><code translate="no" dir="ltr"><span class="devsite-syntax-kn">import</span> <span class="devsite-syntax-s1">'package:flutter/material.dart'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-kn">import</span> <span class="devsite-syntax-s1">'data.dart'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-n">void</span> <span class="devsite-syntax-n">main</span><span class="devsite-syntax-p">()</span> <span class="devsite-syntax-p">{</span> <span class="devsite-syntax-n">runApp</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">const</span> <span class="devsite-syntax-n">DocumentApp</span><span class="devsite-syntax-p">());</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-k">class</span> <span class="devsite-syntax-nc">DocumentApp</span> <span class="devsite-syntax-n">extends</span> <span class="devsite-syntax-n">StatelessWidget</span> <span class="devsite-syntax-p">{</span> <span class="devsite-syntax-n">const</span> <span class="devsite-syntax-n">DocumentApp</span><span class="devsite-syntax-p">({</span><span class="devsite-syntax-nb">super</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">key</span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-nd">@override</span> <span class="devsite-syntax-n">Widget</span> <span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span> <span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span> <span class="devsite-syntax-p">{</span> <span class="devsite-syntax-k">return</span> <span class="devsite-syntax-n">MaterialApp</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-n">theme</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-n">ThemeData</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">useMaterial3</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-n">true</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-n">home</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-n">DocumentScreen</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-n">document</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-n">Document</span><span class="devsite-syntax-p">(),</span> <span class="devsite-syntax-p">),</span> <span class="devsite-syntax-p">);</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-k">class</span> <span class="devsite-syntax-nc">DocumentScreen</span> <span class="devsite-syntax-n">extends</span> <span class="devsite-syntax-n">StatelessWidget</span> <span class="devsite-syntax-p">{</span> <span class="devsite-syntax-n">final</span> <span class="devsite-syntax-n">Document</span> <span class="devsite-syntax-n">document</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-n">const</span> <span class="devsite-syntax-n">DocumentScreen</span><span class="devsite-syntax-p">({</span> <span class="devsite-syntax-n">required</span> <span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">document</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-nb">super</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">key</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-p">});</span> <span class="devsite-syntax-nd">@override</span> <span class="devsite-syntax-n">Widget</span> <span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span> <span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span> <span class="devsite-syntax-p">{</span> <span class="devsite-syntax-k">return</span> <span class="devsite-syntax-n">Scaffold</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-n">appBar</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-n">AppBar</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-n">const</span> <span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Title goes here'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-p">),</span> <span class="devsite-syntax-n">body</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-n">const</span> <span class="devsite-syntax-n">Column</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-p">[</span> <span class="devsite-syntax-n">Center</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Body goes here'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-p">),</span> <span class="devsite-syntax-p">],</span> <span class="devsite-syntax-p">),</span> <span class="devsite-syntax-p">);</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <p>You added the following two widgets to the app:</p> <ul> <li><code translate="no" dir="ltr">DocumentApp</code> sets up the latest version of <a href="https://docs.flutter.dev/development/ui/material" target="_blank">Material Design</a> for theming the UI.</li> <li><code translate="no" dir="ltr">DocumentScreen</code> provides the visual layout of the page using the <code translate="no" dir="ltr">Scaffold</code> widget.</li> </ul> <aside class="special"><p><strong>Tip:</strong> Splitting your UI into separate widgets reduces the size of your <code translate="no" dir="ltr">build()</code> methods.</p> </aside> <ol type="1" start="2"> <li>To make sure everything is running smoothly, run the app on your host machine by clicking <strong>Run and Debug</strong>:</li> </ol> <p class="image-container"><img alt="An image of the 'Run and debug' button, available in 'Run and debug' section of the activity bar on the left hand side." style="width: 373.93px" src="/static/codelabs/dart-patterns-records/img/5c94e1e6b8a47a3.png" srcset="https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5c94e1e6b8a47a3_36.png 36w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5c94e1e6b8a47a3_48.png 48w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5c94e1e6b8a47a3_72.png 72w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5c94e1e6b8a47a3_96.png 96w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5c94e1e6b8a47a3_480.png 480w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5c94e1e6b8a47a3_720.png 720w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5c94e1e6b8a47a3_856.png 856w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5c94e1e6b8a47a3_960.png 960w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5c94e1e6b8a47a3_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5c94e1e6b8a47a3_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5c94e1e6b8a47a3_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <ol type="1" start="3"> <li>By default, Flutter chooses whichever target platform is available. To change the target platform, select the current platform on the Status Bar:</li> </ol> <p class="image-container"><img alt="A screenshot of the target platform selector in VS Code." style="width: 624.00px" src="/static/codelabs/dart-patterns-records/img/53a9cc4ab7da6d00.png" srcset="https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/53a9cc4ab7da6d00_36.png 36w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/53a9cc4ab7da6d00_48.png 48w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/53a9cc4ab7da6d00_72.png 72w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/53a9cc4ab7da6d00_96.png 96w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/53a9cc4ab7da6d00_480.png 480w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/53a9cc4ab7da6d00_720.png 720w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/53a9cc4ab7da6d00_856.png 856w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/53a9cc4ab7da6d00_960.png 960w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/53a9cc4ab7da6d00_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/53a9cc4ab7da6d00_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/53a9cc4ab7da6d00_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>You should see an empty frame with the <code translate="no" dir="ltr">title</code> and <code translate="no" dir="ltr">body</code> elements defined in the <code translate="no" dir="ltr">DocumentScreen</code> widget:</p> <p class="image-container"><img alt="A screenshot of the application built in this step." style="width: 624.00px" src="/static/codelabs/dart-patterns-records/img/b801d79c60a6919.png" srcset="https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/b801d79c60a6919_36.png 36w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/b801d79c60a6919_48.png 48w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/b801d79c60a6919_72.png 72w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/b801d79c60a6919_96.png 96w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/b801d79c60a6919_480.png 480w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/b801d79c60a6919_720.png 720w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/b801d79c60a6919_856.png 856w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/b801d79c60a6919_960.png 960w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/b801d79c60a6919_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/b801d79c60a6919_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/b801d79c60a6919_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> </google-codelab-step> <google-codelab-step label="Create and return records" duration="3" step="4"> <h2 class="step-title" id="4" data-text="Create and return records" tabindex="-1"> 5. Create and return records </h2> <p>In this step, you use records to return multiple values from a function call. Then, you call that function in the <code translate="no" dir="ltr">DocumentScreen</code> widget to access the values and reflect them in the UI.</p> <h2 is-upgraded id="create-and-return-a-record" data-text="Create and return a record" tabindex="-1">Create and return a record</h2> <ul> <li>In <code translate="no" dir="ltr">data.dart</code>, add a new getter method to the Document class called <code translate="no" dir="ltr">metadata</code> that returns a record:</li> </ul> <h3 is-upgraded id="libdata.dart_1" data-text="lib/data.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/dart-patterns-and-records/step_05/lib/data.dart" target="_blank">lib/data.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Python"><code translate="no" dir="ltr"><span class="devsite-syntax-kn">import</span> <span class="devsite-syntax-s1">'dart:convert'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-k">class</span> <span class="devsite-syntax-nc">Document</span> <span class="devsite-syntax-p">{</span> <span class="devsite-syntax-n">final</span> <span class="devsite-syntax-n">Map<String</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">Object</span><span class="devsite-syntax-err">?</span>> <span class="devsite-syntax-n">_json</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-n">Document</span><span class="devsite-syntax-p">()</span> <span class="devsite-syntax-p">:</span> <span class="devsite-syntax-n">_json</span> <span class="devsite-syntax-o">=</span> <span class="devsite-syntax-n">jsonDecode</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">documentJson</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">String</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-p">{</span><span class="devsite-syntax-n">DateTime</span> <span class="devsite-syntax-n">modified</span><span class="devsite-syntax-p">})</span> <span class="devsite-syntax-n">get</span> <span class="devsite-syntax-n">metadata</span> <span class="devsite-syntax-p">{</span> <span class="devsite-syntax-o">//</span> <span class="devsite-syntax-n">Add</span> <span class="devsite-syntax-kn">from</span> <span class="devsite-syntax-nn">here...</span> <span class="devsite-syntax-n">const</span> <span class="devsite-syntax-n">title</span> <span class="devsite-syntax-o">=</span> <span class="devsite-syntax-s1">'My Document'</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-n">final</span> <span class="devsite-syntax-n">now</span> <span class="devsite-syntax-o">=</span> <span class="devsite-syntax-n">DateTime</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">now</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-k">return</span> <span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-n">modified</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-n">now</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-o">//</span> <span class="devsite-syntax-n">to</span> <span class="devsite-syntax-n">here</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <p>The return type for this function is a record with two fields, one with the type <code translate="no" dir="ltr">String</code>, and the other with the type <code translate="no" dir="ltr">DateTime</code>.</p> <p>The return statement constructs a new record by enclosing the two values in parenthesis, <code translate="no" dir="ltr">(title, modified: now)</code>.</p> <p>The first field is positional and unnamed, and the second field is named <code translate="no" dir="ltr">modified</code>.</p> <aside class="special"><p><strong>Summary:</strong></p> <ul> <li>Records are comma-delimited field lists enclosed in parentheses.</li> <li>Record fields can each have a different type, so records can collect multiple types.</li> <li>Records can contain both named and positional fields, like argument lists in a function.</li> <li>Records can be returned from a function, so they enable you to return multiple values from a function call.</li> </ul> </aside> <h2 is-upgraded id="access-record-fields" data-text="Access record fields" tabindex="-1"><strong>Access record fields</strong></h2> <ol type="1"> <li>In the <code translate="no" dir="ltr">DocumentScreen</code> widget, call the <code translate="no" dir="ltr">metadata</code> getter method in the <code translate="no" dir="ltr">build</code> method so that you can get your record and access its values:</li> </ol> <h3 is-upgraded id="libmain.dart_1" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/dart-patterns-and-records/step_05/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">DocumentScreen</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">StatelessWidget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Document</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">document</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">DocumentScreen</span><span class="devsite-syntax-p">({</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">required</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">document</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">super</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">key</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">metadataRecord</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">document</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">metadata</span><span class="devsite-syntax-p">;</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Add</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">line</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Scaffold</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appBar</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">AppBar</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">metadataRecord</span><span class="devsite-syntax-o">.$</span><span class="devsite-syntax-mi">1</span><span class="devsite-syntax-p">),</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Modify</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">line</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">body</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Column</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Center</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'Last modified ${metadataRecord.modified}'</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">And</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">one</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <p>The <code translate="no" dir="ltr">metadata</code> getter method returns a record, which is assigned to the local variable <code translate="no" dir="ltr">metadataRecord</code>. Records are a light and easy way to return multiple values from a single function call and assign them to a variable.</p> <p>To access the individual fields composed in that record, you can use records' built-in getter syntax.</p> <ul> <li>To get a positional field (a field without a name, like <code translate="no" dir="ltr">title</code>), use the getter <code translate="no" dir="ltr">$<num></code> on the record. This returns only unnamed fields.</li> <li>Named fields like <code translate="no" dir="ltr">modified</code> don't have a positional getter, so you can use its name directly, like <code translate="no" dir="ltr">metadataRecord.modified</code>.</li> </ul> <p>To determine the name of a getter for a positional field, start at <code translate="no" dir="ltr">$1</code> and skip named fields. For example:</p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-k">var</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">record</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">named</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'v'</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'y'</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">named2</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'x'</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'z'</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-nb">print</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">record</span><span class="devsite-syntax-o">.$</span><span class="devsite-syntax-mi">1</span><span class="devsite-syntax-p">);</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb">prints</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">y</span> <span class="devsite-syntax-nb">print</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">record</span><span class="devsite-syntax-o">.$</span><span class="devsite-syntax-mi">2</span><span class="devsite-syntax-p">);</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb">prints</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">z</span> </code></pre></devsite-code> <ol type="1" start="2"> <li>Hot reload to see the JSON values displayed in the app. The VS Code Dart plugin hot-reloads every time you save a file.</li> </ol> <p class="image-container"><img alt="A screenshot of the app, which displays the title and modified date." style="width: 624.00px" src="/static/codelabs/dart-patterns-records/img/5ac62325ffd72020.png" srcset="https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5ac62325ffd72020_36.png 36w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5ac62325ffd72020_48.png 48w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5ac62325ffd72020_72.png 72w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5ac62325ffd72020_96.png 96w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5ac62325ffd72020_480.png 480w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5ac62325ffd72020_720.png 720w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5ac62325ffd72020_856.png 856w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5ac62325ffd72020_960.png 960w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5ac62325ffd72020_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5ac62325ffd72020_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5ac62325ffd72020_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>You can see that each field did, in fact, maintain its type.</p> <ul> <li>The <code translate="no" dir="ltr">Text()</code> method takes a String as its first argument.</li> <li>The <code translate="no" dir="ltr">modified</code> field is a DateTime, and is converted into a <code translate="no" dir="ltr">String</code> using <a href="https://dart.dev/language/built-in-types#strings" target="_blank">string interpolation</a>.</li> </ul> <p>The other type-safe way to return different types of data is to define a class, which is more verbose.</p> </google-codelab-step> <google-codelab-step label="Match and destructure with patterns" duration="2" step="5"> <h2 class="step-title" id="5" data-text="Match and destructure with patterns" tabindex="-1"> 6. Match and destructure with patterns </h2> <p>Records can efficiently collect different types of data and easily pass it around. Now, improve your code using <em>patterns</em>.</p> <p>A pattern represents a structure that one or more values can take, like a blueprint. Patterns compare against actual values to determine if they <em>match</em>.</p> <p>Some patterns, when they match, <em>destructure</em> the matched value by pulling data out of it. Destructuring lets you unpack values from an object to assign them to local variables, or perform further matching on them.</p> <h2 is-upgraded id="destructure-a-record-into-local-variables" data-text="Destructure a record into local variables" tabindex="-1">Destructure a record into local variables</h2> <ol type="1"> <li>Refactor the <code translate="no" dir="ltr">build</code> method of <code translate="no" dir="ltr">DocumentScreen</code> to call <code translate="no" dir="ltr">metadata</code> and use it to initialize a <em>pattern variable declaration</em>:</li> </ol> <h3 is-upgraded id="libmain.dart_2" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/dart-patterns-and-records/step_06_a/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">DocumentScreen</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">StatelessWidget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Document</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">document</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">DocumentScreen</span><span class="devsite-syntax-p">({</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">required</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">document</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">super</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">key</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">modified</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">modified</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">document</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">metadata</span><span class="devsite-syntax-p">;</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Modify</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Scaffold</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appBar</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">AppBar</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">),</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Modify</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">body</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Column</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Center</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'Last modified $modified'</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Modify</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <p>The record pattern <code translate="no" dir="ltr">(title, modified: modified)</code> contains two <em>variable patterns</em> that match against the fields of the record returned by <code translate="no" dir="ltr">metadata</code>.</p> <ul> <li>The expression matches the subpattern because the result is a record with two fields, one of which is named <code translate="no" dir="ltr">modified</code>.</li> <li>Because they match, the variable declaration pattern destructures the expression, accessing its values and binding them to new local variables of the same types and names, <code translate="no" dir="ltr">String title</code> and <code translate="no" dir="ltr">DateTime modified</code>.</li> </ul> <p>There is a shorthand for when the name of a field and the variable populating it are the same. Refactor the <code translate="no" dir="ltr">build</code> method of <code translate="no" dir="ltr">DocumentScreen</code> as follows.</p> <h3 is-upgraded id="libmain.dart_3" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/dart-patterns-and-records/step_06_b/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">DocumentScreen</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">StatelessWidget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Document</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">document</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">DocumentScreen</span><span class="devsite-syntax-p">({</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">required</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">document</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">super</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">key</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-n">modified</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">document</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">metadata</span><span class="devsite-syntax-p">;</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Modify</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Scaffold</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appBar</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">AppBar</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">body</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Column</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Center</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'Last modified $modified'</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <p>The syntax of the variable pattern <code translate="no" dir="ltr">:modified</code> is shorthand for <code translate="no" dir="ltr">modified: modified</code>. If you want a new local variable of a different name, you can write <code translate="no" dir="ltr">modified: localModified</code> instead.</p> <ol type="1" start="2"> <li>Hot reload to see the same result as in the previous step. The behavior is exactly the same; you just made your code more concise.</li> </ol> </google-codelab-step> <google-codelab-step label="Use patterns to extract data" duration="5" step="6"> <h2 class="step-title" id="6" data-text="Use patterns to extract data" tabindex="-1"> 7. Use patterns to extract data </h2> <p>In certain contexts, patterns don't only match and destructure but can also make a <em>decision</em> about <em>what the code does</em>, based on whether or not the pattern matches. These are called <em>refutable patterns</em>.</p> <p>The variable declaration pattern you used in the last step is an <em>irrefutable pattern</em>: the value must match the pattern or it's an error and destructuring won't happen. Think of any variable declaration or assignment; you can't assign a value to a variable if they're not the same type.</p> <p>Refutable patterns, on the other hand, are used in control flow contexts:</p> <ul> <li>They <em>expect</em> that some values they compare against will not match.</li> <li>They are meant to <em>influence the control flow</em>, based on whether or not the value matches.</li> <li>They <em>don't interrupt execution</em> with an error if they don't match, they just move to the next statement.</li> <li>They can destructure and bind variables that are <em>only usable</em> when they match</li> </ul> <h2 is-upgraded id="read-json-values-without-patterns" data-text="Read JSON values without patterns" tabindex="-1"><strong>Read JSON values without patterns</strong></h2> <p>In this section, you read data without pattern matching to see how patterns can help you work with JSON data.</p> <ul> <li>Replace the previous version of <code translate="no" dir="ltr">metadata</code> with one that reads values from the <code translate="no" dir="ltr">_json</code> map. Copy and paste this version of <code translate="no" dir="ltr">metadata</code> into the <code translate="no" dir="ltr">Document</code> class:</li> </ul> <h3 is-upgraded id="libdata.dart_2" data-text="lib/data.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/dart-patterns-and-records/step_07_a/lib/data.dart" target="_blank">lib/data.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Document</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Map<String</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">Object</span><span class="devsite-syntax-err">?</span>><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">_json</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Document</span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">_json</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">jsonDecode</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">documentJson</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nb devsite-syntax-nb-Type">String</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span><span class="devsite-syntax-n">DateTime</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">modified</span><span class="devsite-syntax-p">})</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">get</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">metadata</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">_json</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">containsKey</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'metadata'</span><span class="devsite-syntax-p">))</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Modify</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">from</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">here</span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">metadataJson</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">_json</span><span class="devsite-syntax-p">[</span><span class="devsite-syntax-s1">'metadata'</span><span class="devsite-syntax-p">];</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">metadataJson</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">is</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Map</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">title</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">metadataJson</span><span class="devsite-syntax-p">[</span><span class="devsite-syntax-s1">'title'</span><span class="devsite-syntax-p">]</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">as</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">String</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">localModified</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">DateTime</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">parse</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">metadataJson</span><span class="devsite-syntax-p">[</span><span class="devsite-syntax-s1">'modified'</span><span class="devsite-syntax-p">]</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">as</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">String</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">modified</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">localModified</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">throw</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">FormatException</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Unexpected JSON'</span><span class="devsite-syntax-p">);</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">to</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">here</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <p>This code validates that the data is structured correctly without using patterns. In a later step, you use pattern matching to perform the same validation using less code. It performs three checks before doing anything else:</p> <ul> <li>The JSON contains the data <em>structure</em> you expect: <code translate="no" dir="ltr">if (_json.containsKey('metadata'))</code></li> <li>The data has the <em>type</em> you expect: <code translate="no" dir="ltr">if (metadataJson is Map)</code></li> <li>That the data is <em>not null</em>, which is implicitly confirmed in the previous check.</li> </ul> <h2 is-upgraded id="read-json-values-using-a-map-pattern" data-text="Read JSON values using a map pattern" tabindex="-1"><strong>Read JSON values using a map pattern</strong></h2> <p>With a refutable pattern, you can verify that the JSON has the expected structure using a <em>map pattern</em>.</p> <ul> <li>Replace the previous version of <code translate="no" dir="ltr">metadata</code> with this code:</li> </ul> <h3 is-upgraded id="libdata.dart_3" data-text="lib/data.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/dart-patterns-and-records/step_07_b/lib/data.dart" target="_blank">lib/data.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Document</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Map<String</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">Object</span><span class="devsite-syntax-err">?</span>><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">_json</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Document</span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">_json</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">jsonDecode</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">documentJson</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nb devsite-syntax-nb-Type">String</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span><span class="devsite-syntax-n">DateTime</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">modified</span><span class="devsite-syntax-p">})</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">get</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">metadata</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">_json</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Modify</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">from</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">here</span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">case</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'metadata'</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'title'</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">String</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'modified'</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">String</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">localModified</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">})</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">modified</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">DateTime</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">parse</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">localModified</span><span class="devsite-syntax-p">));</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">else</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">throw</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">FormatException</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Unexpected JSON'</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">to</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">here</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <p>Here, you see a new kind of if-statement (introduced in Dart 3), the <em>if-case</em>. The case body only executes if the case pattern matches the data in <code translate="no" dir="ltr">_json</code>. This match accomplishes the same checks you wrote in the first version of <code translate="no" dir="ltr">metadata</code> to validate the incoming JSON. This code validates the following:</p> <ul> <li><code translate="no" dir="ltr">_json</code> is a Map type.</li> <li><code translate="no" dir="ltr">_json</code> contains a <code translate="no" dir="ltr">metadata</code> key.</li> <li><code translate="no" dir="ltr">_json</code> is not null.</li> <li><code translate="no" dir="ltr">_json['metadata']</code> is also a Map type.</li> <li><code translate="no" dir="ltr">_json['metadata']</code> contains the keys <code translate="no" dir="ltr">title</code> and <code translate="no" dir="ltr">modified</code>.</li> <li><code translate="no" dir="ltr">title</code> and <code translate="no" dir="ltr">localModified</code> are strings and aren't null.</li> </ul> <p>If the value doesn't match, the <em>pattern refutes</em> (refuses to continue execution) and proceeds to the <code translate="no" dir="ltr">else</code> clause. If the match is successful, the pattern destructures the values of <code translate="no" dir="ltr">title</code> and <code translate="no" dir="ltr">modified</code> from the map and binds them to new local variables.</p> <p>For a full list of patterns, see the <a href="https://github.com/dart-lang/language/blob/master/accepted/future-releases/0546-patterns/feature-specification.md#patterns" target="_blank">table in the Patterns section</a> of the feature specification.</p> <aside class="special"><p><strong>Summary:</strong> Using patterns in this step tests types, destructures, and binds values using a single statement.</p> </aside> </google-codelab-step> <google-codelab-step label="Prepare the app for more patterns" duration="2" step="7"> <h2 class="step-title" id="7" data-text="Prepare the app for more patterns" tabindex="-1"> 8. Prepare the app for more patterns </h2> <p>So far, you address the <code translate="no" dir="ltr">metadata</code> part of the JSON data. In this step, you refine your business logic a bit more in order to handle the data in the <code translate="no" dir="ltr">blocks</code> list and render it into your app.</p> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Carbon"><code translate="no" dir="ltr"><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-s">"metadata"</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// ...</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">},</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-s">"blocks"</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-s">"type"</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s">"h1"</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-s">"text"</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s">"Chapter 1"</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">},</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-c1">// ...</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">]</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <h2 is-upgraded id="create-a-class-that-stores-data" data-text="Create a class that stores data" tabindex="-1">Create a class that stores data</h2> <ul> <li>Add a new class, <code translate="no" dir="ltr">Block</code>, to <code translate="no" dir="ltr">data.dart</code>, which is used to read and store the data for one of the blocks in the JSON data.</li> </ul> <h3 is-upgraded id="libdata.dart_4" data-text="lib/data.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/dart-patterns-and-records/step_08/lib/data.dart" target="_blank">lib/data.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Block</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">String</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">type</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">String</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Block</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">type</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">factory</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Block</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">fromJson</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">Map<String</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">dynamic</span>><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">json</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">json</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">case</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span><span class="devsite-syntax-s1">'type'</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">type</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'text'</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">})</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Block</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">type</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">else</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">throw</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">FormatException</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Unexpected JSON format'</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <p>The factory constructor <code translate="no" dir="ltr">fromJson()</code> uses the same if-case with a map pattern that you've seen before.</p> <p>Notice that the <code translate="no" dir="ltr">json</code> matches the map pattern, even though one of the keys, <code translate="no" dir="ltr">checked</code>, is not accounted for in the pattern. Map patterns ignore any entries in the map object that aren't explicitly accounted for in the pattern.</p> <h2 is-upgraded id="return-a-list-of-block-objects" data-text="Return a list of Block objects" tabindex="-1">Return a list of Block objects</h2> <ul> <li>Next, add a new function, <code translate="no" dir="ltr">getBlocks()</code>, to the <code translate="no" dir="ltr">Document</code> class. <code translate="no" dir="ltr">getBlocks()</code> parses the JSON into instances of the <code translate="no" dir="ltr">Block</code> class and returns a list of blocks to render in your UI:</li> </ul> <h3 is-upgraded id="libdata.dart_5" data-text="lib/data.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/dart-patterns-and-records/step_08/lib/data.dart" target="_blank">lib/data.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Document</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Map<String</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">Object</span><span class="devsite-syntax-err">?</span>><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">_json</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Document</span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">_json</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">jsonDecode</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">documentJson</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-nb devsite-syntax-nb-Type">String</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span><span class="devsite-syntax-n">DateTime</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">modified</span><span class="devsite-syntax-p">})</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">get</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">metadata</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">_json</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">case</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'metadata'</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'title'</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">String</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'modified'</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">String</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">localModified</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">})</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">modified</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">DateTime</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">parse</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">localModified</span><span class="devsite-syntax-p">));</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">else</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">throw</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">FormatException</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Unexpected JSON'</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">List<Block></span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">getBlocks</span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Add</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">from</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">here</span><span class="devsite-syntax-o">...</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">if</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">_json</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">case</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span><span class="devsite-syntax-s1">'blocks'</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">List</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">blocksJson</span><span class="devsite-syntax-p">})</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span><span class="devsite-syntax-k">for</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">blockJson</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-ow">in</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">blocksJson</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Block</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">fromJson</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">blockJson</span><span class="devsite-syntax-p">)];</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">else</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">throw</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">FormatException</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Unexpected JSON format'</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">to</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">here</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <p>The <code translate="no" dir="ltr">getBlocks()</code> function returns a list of <code translate="no" dir="ltr">Block</code> objects, which you use later to build the UI. A familiar if-case statement performs validation and casts the value of the <code translate="no" dir="ltr">blocks</code> metadata into a new <code translate="no" dir="ltr">List</code> named <code translate="no" dir="ltr">blocksJson</code> (without patterns, you'd need the <a href="https://api.dart.dev/stable/dart-core/Iterable/toList.html" target="_blank"><code translate="no" dir="ltr">toList()</code></a> method to cast).</p> <p>The list literal contains a <a href="https://dart.dev/language/collections#collection-operators" target="_blank">collection for</a> in order to fill the new list with <code translate="no" dir="ltr">Block</code> objects.</p> <p>This section doesn't introduce any pattern-related features you haven't already tried in this codelab. In the next step, you prepare to render the list items in your UI.</p> </google-codelab-step> <google-codelab-step label="Use patterns to display the document" duration="4" step="8"> <h2 class="step-title" id="8" data-text="Use patterns to display the document" tabindex="-1"> 9. Use patterns to display the document </h2> <p>You now successfully destructure and recompose your JSON data, using an if-case statement and refutable patterns. But if-case is only one of the enhancements to control flow structures that come with patterns. Now, you apply your knowledge of refutable patterns to switch statements.</p> <h2 is-upgraded id="control-whats-rendered-using-patterns-with-switch-statements" data-text="Control what's rendered using patterns with switch statements" tabindex="-1">Control what's rendered using patterns with switch statements</h2> <ul> <li>In <code translate="no" dir="ltr">main.dart</code>, create a new widget, <code translate="no" dir="ltr">BlockWidget</code>, that determines the styling of each block based on its <code translate="no" dir="ltr">type</code> field.</li> </ul> <h3 is-upgraded id="libmain.dart_4" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/dart-patterns-and-records/step_09/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">BlockWidget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">StatelessWidget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Block</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">block</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">BlockWidget</span><span class="devsite-syntax-p">({</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">required</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">block</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">super</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">key</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">TextStyle</span><span class="devsite-syntax-err">?</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">textStyle</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">switch</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">block</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">type</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">case</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'h1'</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">textStyle</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Theme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">of</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">textTheme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">displayMedium</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">case</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'p'</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">||</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'checkbox'</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">textStyle</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Theme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">of</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">textTheme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">bodyMedium</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">case</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">_</span><span class="devsite-syntax-p">:</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">textStyle</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Theme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">of</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">textTheme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">bodySmall</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Container</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">margin</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">EdgeInsets</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">all</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-mi">8</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">block</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">style</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">textStyle</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <p>The switch statement in the <code translate="no" dir="ltr">build</code> method switches on the <code translate="no" dir="ltr">type</code> field of the <code translate="no" dir="ltr">block</code> object.</p> <ol type="1"> <li>The first case statement uses a <em>constant string pattern</em>. The pattern matches if <code translate="no" dir="ltr">block.type</code> is equal to the constant value <code translate="no" dir="ltr">h1</code>.</li> <li>The second case statement uses a <em>logical-or pattern</em> with two constant string patterns as its subpatterns. The pattern matches if <code translate="no" dir="ltr">block.type</code> matches either of the subpatterns <code translate="no" dir="ltr">p</code> or <code translate="no" dir="ltr">checkbox</code>.</li> </ol> <aside class="special"><p><strong>Did you know? </strong><em>logical-and patterns</em> (<code translate="no" dir="ltr">&&</code>) can also be used.</p> </aside> <ol type="1" start="3"> <li>The final case is a <em>wildcard pattern</em>, <code translate="no" dir="ltr">_</code>. Wildcards in switch cases match everything else. They behave the same as <code translate="no" dir="ltr">default</code> clauses, which are still allowed in switch statements (they're just a little more verbose).</li> </ol> <p>Wildcard patterns can be used wherever a pattern is allowed—for example, in a variable declaration pattern: <code translate="no" dir="ltr">var (title, _) = document.metadata;</code></p> <p>In this context, the wildcard doesn't bind any variable. It discards the second field.</p> <aside class="special"><p><strong>Note:</strong> Switch statements no longer require <code translate="no" dir="ltr">break</code> as of Dart 3. Non-empty cases jump to the end of the statement when they reach the end of their body.</p> </aside> <p>In the next section, you learn about more switch features after displaying the <code translate="no" dir="ltr">Block</code> objects.</p> <h2 is-upgraded id="display-the-document-content" data-text="Display the document content" tabindex="-1">Display the document content</h2> <p>Create a local variable that contains the list of <code translate="no" dir="ltr">Block</code> objects by calling <code translate="no" dir="ltr">getBlocks()</code> in the <code translate="no" dir="ltr">DocumentScreen</code> widget's <code translate="no" dir="ltr">build</code> method.</p> <ol type="1"> <li>Replace the existing <code translate="no" dir="ltr">build</code> method in <code translate="no" dir="ltr">DocumentationScreen</code> with this version:</li> </ol> <h3 is-upgraded id="libmain.dart_5" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/dart-patterns-and-records/step_09/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">DocumentScreen</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">StatelessWidget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Document</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">document</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">DocumentScreen</span><span class="devsite-syntax-p">({</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">required</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">document</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">super</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">key</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-n">modified</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">document</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">metadata</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">blocks</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">document</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">getBlocks</span><span class="devsite-syntax-p">();</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Add</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">line</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Scaffold</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appBar</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">AppBar</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">body</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Column</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Last modified: $modified'</span><span class="devsite-syntax-p">),</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Modify</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">from</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">here</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Expanded</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ListView</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">builder</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">itemCount</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">blocks</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">length</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">itemBuilder</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">index</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">BlockWidget</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">block</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">blocks</span><span class="devsite-syntax-p">[</span><span class="devsite-syntax-n">index</span><span class="devsite-syntax-p">]);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">},</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">to</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">here</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <p>The line <code translate="no" dir="ltr">BlockWidget(block: blocks[index])</code> constructs a <code translate="no" dir="ltr">BlockWidget</code> widget for each item in the list of blocks returned from the <code translate="no" dir="ltr">getBlocks()</code> method.</p> <ol type="1" start="2"> <li>Run the application, and then you should see the blocks appearing on screen:</li> </ol> <p class="image-container"><img alt="Screenshot of the app displaying content from the 'blocks' section of the JSON data." style="width: 624.00px" src="/static/codelabs/dart-patterns-records/img/82aa53d020fc3e05.png" srcset="https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/82aa53d020fc3e05_36.png 36w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/82aa53d020fc3e05_48.png 48w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/82aa53d020fc3e05_72.png 72w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/82aa53d020fc3e05_96.png 96w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/82aa53d020fc3e05_480.png 480w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/82aa53d020fc3e05_720.png 720w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/82aa53d020fc3e05_856.png 856w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/82aa53d020fc3e05_960.png 960w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/82aa53d020fc3e05_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/82aa53d020fc3e05_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/82aa53d020fc3e05_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> </google-codelab-step> <google-codelab-step label="Use switch expressions" duration="4" step="9"> <h2 class="step-title" id="9" data-text="Use switch expressions" tabindex="-1"> 10. Use switch expressions </h2> <p>Patterns add a lot of capabilities to <code translate="no" dir="ltr">switch</code> and <code translate="no" dir="ltr">case</code>. To make them usable in more places, Dart has <em>switch expressions</em>. A series of cases can provide a value directly to a variable assignment or return statement.</p> <h2 is-upgraded id="convert-the-switch-statement-into-a-switch-expression" data-text="Convert the switch statement into a switch expression" tabindex="-1">Convert the switch statement into a switch expression</h2> <p>The Dart analyzer provides <em>assists</em> to help you make changes to your code.</p> <ol type="1"> <li>Move your cursor to the switch statement from the previous section.</li> <li>Click on the lightbulb to view the available assists.</li> <li>Select the <strong>Convert to switch expression</strong> assist.</li> </ol> <p class="image-container"><img alt="A screenshot of the 'convert to switch expression' assist available in VS Code." style="width: 624.00px" src="/static/codelabs/dart-patterns-records/img/c1623411a5861516.png" srcset="https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/c1623411a5861516_36.png 36w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/c1623411a5861516_48.png 48w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/c1623411a5861516_72.png 72w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/c1623411a5861516_96.png 96w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/c1623411a5861516_480.png 480w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/c1623411a5861516_720.png 720w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/c1623411a5861516_856.png 856w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/c1623411a5861516_960.png 960w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/c1623411a5861516_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/c1623411a5861516_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/c1623411a5861516_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>The new version of this code looks like this:</p> <h3 is-upgraded id="libmain.dart_6" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/dart-patterns-and-records/step_10/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">BlockWidget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">StatelessWidget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Block</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">block</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">BlockWidget</span><span class="devsite-syntax-p">({</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">required</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">block</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">super</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">key</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">TextStyle</span><span class="devsite-syntax-err">?</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">textStyle</span><span class="devsite-syntax-p">;</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Modify</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">from</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">here</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">textStyle</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">switch</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">block</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">type</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'h1'</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Theme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">of</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">textTheme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">displayMedium</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'p'</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">||</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'checkbox'</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Theme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">of</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">textTheme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">bodyMedium</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">_</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Theme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">of</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">textTheme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">bodySmall</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">};</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">to</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">here</span><span class="devsite-syntax-o">.</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Container</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">margin</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">EdgeInsets</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">all</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-mi">8</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">block</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">style</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">textStyle</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <p>A switch expression looks similar to a switch statement, but it eliminates the <code translate="no" dir="ltr">case</code> keyword and uses <code translate="no" dir="ltr">=></code> to separate the pattern from the case body. Unlike switch statements, switch expressions return a value and can be used anywhere an expression can be used.</p> </google-codelab-step> <google-codelab-step label="Use object patterns" duration="4" step="10"> <h2 class="step-title" id="10" data-text="Use object patterns" tabindex="-1"> 11. Use object patterns </h2> <p>Dart is an object-oriented language, so patterns apply to all objects. In this step, you switch on an <em>object pattern</em> and destructure object properties to enhance the date rendering logic of your UI.</p> <aside class="special"><p><strong>Note:</strong> There's no migration necessary to support patterns; you can immediately start using pattern matching on your existing Dart classes.</p> </aside> <h2 is-upgraded id="extract-properties-from-object-patterns" data-text="Extract properties from object patterns" tabindex="-1"><strong>Extract properties from object patterns</strong></h2> <p>In this section, you improve how the last modified date is displayed using patterns.</p> <ul> <li>Add the <code translate="no" dir="ltr">formatDate</code> method to <code translate="no" dir="ltr">main.dart</code>:</li> </ul> <h3 is-upgraded id="libmain.dart_7" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/dart-patterns-and-records/step_11_a/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Genshi"><code translate="no" dir="ltr">String<span class="devsite-syntax-w"> </span>formatDate(DateTime<span class="devsite-syntax-w"> </span>dateTime)<span class="devsite-syntax-w"> </span>{ <span class="devsite-syntax-w"> </span>final<span class="devsite-syntax-w"> </span>today<span class="devsite-syntax-w"> </span>=<span class="devsite-syntax-w"> </span>DateTime.now(); <span class="devsite-syntax-w"> </span>final<span class="devsite-syntax-w"> </span>difference<span class="devsite-syntax-w"> </span>=<span class="devsite-syntax-w"> </span>dateTime.difference(today); <span class="devsite-syntax-w"> </span>return<span class="devsite-syntax-w"> </span>switch<span class="devsite-syntax-w"> </span>(difference)<span class="devsite-syntax-w"> </span>{ <span class="devsite-syntax-w"> </span>Duration(inDays:<span class="devsite-syntax-w"> </span>0)<span class="devsite-syntax-w"> </span>=><span class="devsite-syntax-w"> </span>'today', <span class="devsite-syntax-w"> </span>Duration(inDays:<span class="devsite-syntax-w"> </span>1)<span class="devsite-syntax-w"> </span>=><span class="devsite-syntax-w"> </span>'tomorrow', <span class="devsite-syntax-w"> </span>Duration(inDays:<span class="devsite-syntax-w"> </span>-1)<span class="devsite-syntax-w"> </span>=><span class="devsite-syntax-w"> </span>'yesterday', <span class="devsite-syntax-w"> </span>Duration(inDays:<span class="devsite-syntax-w"> </span>final<span class="devsite-syntax-w"> </span>days,<span class="devsite-syntax-w"> </span>isNegative:<span class="devsite-syntax-w"> </span>true)<span class="devsite-syntax-w"> </span>=><span class="devsite-syntax-w"> </span>'<span class="devsite-syntax-cp">${</span><span class="devsite-syntax-n">days</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">abs</span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-cp">}</span><span class="devsite-syntax-w"> </span>days<span class="devsite-syntax-w"> </span>ago', <span class="devsite-syntax-w"> </span>Duration(inDays:<span class="devsite-syntax-w"> </span>final<span class="devsite-syntax-w"> </span>days)<span class="devsite-syntax-w"> </span>=><span class="devsite-syntax-w"> </span>'<span class="devsite-syntax-nv">$days</span><span class="devsite-syntax-w"> </span>days<span class="devsite-syntax-w"> </span>from<span class="devsite-syntax-w"> </span>now', <span class="devsite-syntax-w"> </span>}; } </code></pre></devsite-code> <p>This method returns a switch expression that switches on the value <code translate="no" dir="ltr">difference</code>, a <a href="https://api.dart.dev/stable/dart-core/Duration-class.html" target="_blank"><code translate="no" dir="ltr">Duration</code></a> object. It represents the span of time between <code translate="no" dir="ltr">today</code> and the <code translate="no" dir="ltr">modified</code> value from the JSON data.</p> <p>Each case of the switch expression is using an object pattern that matches by calling getters on the object's properties <code translate="no" dir="ltr">inDays</code> and <code translate="no" dir="ltr">isNegative</code>. The syntax looks like it might be constructing a Duration object, but it's actually accessing fields on the <code translate="no" dir="ltr">difference</code> object.</p> <p>The first three cases use constant subpatterns <code translate="no" dir="ltr">0</code>, <code translate="no" dir="ltr">1</code>, and <code translate="no" dir="ltr">-1</code> to match the object property <code translate="no" dir="ltr">inDays</code> and return the corresponding string.</p> <p>The last two cases handle durations beyond today, yesterday, and tomorrow:</p> <ul> <li>If the <code translate="no" dir="ltr">isNegative</code> property matches the <em>boolean constant pattern </em><code translate="no" dir="ltr">true</code>, meaning the modification date was in the past, it displays <em>days ago</em>.</li> <li>If that case doesn't catch the difference, then duration must be a positive number of days (no need to explicitly verify with <code translate="no" dir="ltr">isNegative: false</code>), so the modification date is in the future and displays <em>days from now</em>.</li> </ul> <h2 is-upgraded id="add-formatting-logic-for-weeks" data-text="Add formatting logic for weeks" tabindex="-1">Add formatting logic for weeks</h2> <ul> <li>Add two new cases to your formatting function in order to identify durations longer than 7 days so that the UI can display them as <em>weeks</em>:</li> </ul> <h3 is-upgraded id="libmain.dart_8" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/dart-patterns-and-records/step_11_b/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="Genshi"><code translate="no" dir="ltr">String<span class="devsite-syntax-w"> </span>formatDate(DateTime<span class="devsite-syntax-w"> </span>dateTime)<span class="devsite-syntax-w"> </span>{ <span class="devsite-syntax-w"> </span>final<span class="devsite-syntax-w"> </span>today<span class="devsite-syntax-w"> </span>=<span class="devsite-syntax-w"> </span>DateTime.now(); <span class="devsite-syntax-w"> </span>final<span class="devsite-syntax-w"> </span>difference<span class="devsite-syntax-w"> </span>=<span class="devsite-syntax-w"> </span>dateTime.difference(today); <span class="devsite-syntax-w"> </span>return<span class="devsite-syntax-w"> </span>switch<span class="devsite-syntax-w"> </span>(difference)<span class="devsite-syntax-w"> </span>{ <span class="devsite-syntax-w"> </span>Duration(inDays:<span class="devsite-syntax-w"> </span>0)<span class="devsite-syntax-w"> </span>=><span class="devsite-syntax-w"> </span>'today', <span class="devsite-syntax-w"> </span>Duration(inDays:<span class="devsite-syntax-w"> </span>1)<span class="devsite-syntax-w"> </span>=><span class="devsite-syntax-w"> </span>'tomorrow', <span class="devsite-syntax-w"> </span>Duration(inDays:<span class="devsite-syntax-w"> </span>-1)<span class="devsite-syntax-w"> </span>=><span class="devsite-syntax-w"> </span>'yesterday', <span class="devsite-syntax-w"> </span>Duration(inDays:<span class="devsite-syntax-w"> </span>final<span class="devsite-syntax-w"> </span>days)<span class="devsite-syntax-w"> </span>when<span class="devsite-syntax-w"> </span>days<span class="devsite-syntax-w"> > </span>7<span class="devsite-syntax-w"> </span>=><span class="devsite-syntax-w"> </span>'<span class="devsite-syntax-cp">${</span><span class="devsite-syntax-n">days</span> <span class="devsite-syntax-o">~/</span> <span class="devsite-syntax-mi">7</span><span class="devsite-syntax-cp">}</span><span class="devsite-syntax-w"> </span>weeks<span class="devsite-syntax-w"> </span>from<span class="devsite-syntax-w"> </span>now',<span class="devsite-syntax-w"> </span>//<span class="devsite-syntax-w"> </span>Add<span class="devsite-syntax-w"> </span>from<span class="devsite-syntax-w"> </span>here <span class="devsite-syntax-w"> </span>Duration(inDays:<span class="devsite-syntax-w"> </span>final<span class="devsite-syntax-w"> </span>days)<span class="devsite-syntax-w"> </span>when<span class="devsite-syntax-w"> </span>days<span class="devsite-syntax-w"> < </span>-7<span class="devsite-syntax-w"> </span>=> <span class="devsite-syntax-w"> </span>'<span class="devsite-syntax-cp">${</span><span class="devsite-syntax-n">days</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">abs</span><span class="devsite-syntax-p">()</span> <span class="devsite-syntax-o">~/</span> <span class="devsite-syntax-mi">7</span><span class="devsite-syntax-cp">}</span><span class="devsite-syntax-w"> </span>weeks<span class="devsite-syntax-w"> </span>ago',<span class="devsite-syntax-w"> </span>//<span class="devsite-syntax-w"> </span>to<span class="devsite-syntax-w"> </span>here. <span class="devsite-syntax-w"> </span>Duration(inDays:<span class="devsite-syntax-w"> </span>final<span class="devsite-syntax-w"> </span>days,<span class="devsite-syntax-w"> </span>isNegative:<span class="devsite-syntax-w"> </span>true)<span class="devsite-syntax-w"> </span>=><span class="devsite-syntax-w"> </span>'<span class="devsite-syntax-cp">${</span><span class="devsite-syntax-n">days</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">abs</span><span class="devsite-syntax-p">()</span><span class="devsite-syntax-cp">}</span><span class="devsite-syntax-w"> </span>days<span class="devsite-syntax-w"> </span>ago', <span class="devsite-syntax-w"> </span>Duration(inDays:<span class="devsite-syntax-w"> </span>final<span class="devsite-syntax-w"> </span>days)<span class="devsite-syntax-w"> </span>=><span class="devsite-syntax-w"> </span>'<span class="devsite-syntax-nv">$days</span><span class="devsite-syntax-w"> </span>days<span class="devsite-syntax-w"> </span>from<span class="devsite-syntax-w"> </span>now', <span class="devsite-syntax-w"> </span>}; } </code></pre></devsite-code> <p>This code introduces <em>guard clauses</em>:</p> <ul> <li>A guard clause uses the <code translate="no" dir="ltr">when</code> keyword after a case pattern.</li> <li>They can be used in if-cases, switch statements, and switch expressions.</li> <li>They only add a condition to a pattern <em>after it's matched</em>.</li> <li>If the guard clause evaluates to false, the entire pattern is <em>refuted</em>, and execution proceeds to the next case.</li> </ul> <h2 is-upgraded id="add-the-newly-formatted-date-to-the-ui" data-text="Add the newly formatted date to the UI" tabindex="-1"><strong>Add the newly formatted date to the UI</strong></h2> <ol type="1"> <li>Finally, update the <code translate="no" dir="ltr">build</code> method in <code translate="no" dir="ltr">DocumentScreen</code> to use the <code translate="no" dir="ltr">formatDate</code> function:</li> </ol> <h3 is-upgraded id="libmain.dart_9" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/dart-patterns-and-records/step_11_b/lib/main.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">DocumentScreen</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">StatelessWidget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Document</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">document</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">DocumentScreen</span><span class="devsite-syntax-p">({</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">required</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">document</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">super</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">key</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-n">modified</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">document</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">metadata</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">formattedModifiedDate</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">formatDate</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">modified</span><span class="devsite-syntax-p">);</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Add</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">line</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">blocks</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">document</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">getBlocks</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Scaffold</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">appBar</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">AppBar</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">title</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">body</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Column</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Last modified: $formattedModifiedDate'</span><span class="devsite-syntax-p">),</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">//</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Modify</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">line</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Expanded</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ListView</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">builder</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">itemCount</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">blocks</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">length</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">itemBuilder</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">index</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">BlockWidget</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">block</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">blocks</span><span class="devsite-syntax-p">[</span><span class="devsite-syntax-n">index</span><span class="devsite-syntax-p">]);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">},</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <ol type="1" start="2"> <li>Hot reload to see the changes in your app:</li> </ol> <p class="image-container"><img alt="A screenshot of the app that displays a string 'Last modified: 2 weeks ago' using the formatDate() function." style="width: 624.00px" src="/static/codelabs/dart-patterns-records/img/3baf66737b86e35e.png" srcset="https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/3baf66737b86e35e_36.png 36w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/3baf66737b86e35e_48.png 48w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/3baf66737b86e35e_72.png 72w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/3baf66737b86e35e_96.png 96w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/3baf66737b86e35e_480.png 480w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/3baf66737b86e35e_720.png 720w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/3baf66737b86e35e_856.png 856w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/3baf66737b86e35e_960.png 960w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/3baf66737b86e35e_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/3baf66737b86e35e_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/3baf66737b86e35e_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> </google-codelab-step> <google-codelab-step label="Seal a class for exhaustive switching" duration="4" step="11"> <h2 class="step-title" id="11" data-text="Seal a class for exhaustive switching" tabindex="-1"> 12. Seal a class for exhaustive switching </h2> <p>Notice that you didn't use a wildcard or default case at the end of the last switch. Though it's good practice to always include a case for values that might fall through, it's ok in a simple example like this since you know the cases you defined account for <em>all of the possible values </em><code translate="no" dir="ltr">inDays</code> could potentially take.</p> <p>When every case in a switch is handled, it's called an <em>exhaustive switch</em>. For example, switching on a <code translate="no" dir="ltr">bool</code> type is exhaustive when it has cases for <code translate="no" dir="ltr">true</code> and <code translate="no" dir="ltr">false</code>. Switching on an <code translate="no" dir="ltr">enum</code> type is exhaustive when there are cases for each of the enum's values, too, because enums represent a <em>fixed number</em> of <em>constant values</em>.</p> <p>Dart 3 extended <em>exhaustiveness checking</em> to objects and class hierarchies with the new class modifier <code translate="no" dir="ltr">sealed</code>. Refactor your <code translate="no" dir="ltr">Block</code> class as a sealed superclass.</p> <h2 is-upgraded id="create-the-subclasses" data-text="Create the subclasses" tabindex="-1">Create the subclasses</h2> <ul> <li>In <code translate="no" dir="ltr">data.dart</code>, create three new classes—<code translate="no" dir="ltr">HeaderBlock</code>, <code translate="no" dir="ltr">ParagraphBlock</code>, and <code translate="no" dir="ltr">CheckboxBlock</code>—that extend <code translate="no" dir="ltr">Block</code>:</li> </ul> <h3 is-upgraded id="libdata.dart_6" data-text="lib/data.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/dart-patterns-and-records/step_12/lib/data.dart" target="_blank">lib/data.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">HeaderBlock</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Block</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">String</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">HeaderBlock</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ParagraphBlock</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Block</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">String</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ParagraphBlock</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-p">}</span> <span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">CheckboxBlock</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Block</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">String</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">bool</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">isChecked</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">CheckboxBlock</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">isChecked</span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <p>Each of these classes corresponds to the different <code translate="no" dir="ltr">type</code> values from the original JSON: <code translate="no" dir="ltr">'h1'</code>, <code translate="no" dir="ltr">'p'</code>, and <code translate="no" dir="ltr">'checkbox'</code>.</p> <h2 is-upgraded id="seal-the-superclass" data-text="Seal the superclass" tabindex="-1"><strong>Seal the superclass</strong></h2> <ul> <li>Mark the <code translate="no" dir="ltr">Block</code> class as <code translate="no" dir="ltr">sealed</code>. Then, refactor the if-case as a switch expression that returns the subclass corresponding to the <code translate="no" dir="ltr">type</code> specified in the JSON:</li> </ul> <h3 is-upgraded id="libdata.dart_7" data-text="lib/data.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/dart-patterns-and-records/step_12/lib/data.dart" target="_blank">lib/data.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-n">sealed</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Block</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Block</span><span class="devsite-syntax-p">();</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">factory</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Block</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">fromJson</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">Map<String</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">Object</span><span class="devsite-syntax-err">?</span>><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">json</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">switch</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">json</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span><span class="devsite-syntax-s1">'type'</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'h1'</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'text'</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">String</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">HeaderBlock</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span><span class="devsite-syntax-s1">'type'</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'p'</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'text'</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">String</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ParagraphBlock</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span><span class="devsite-syntax-s1">'type'</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'checkbox'</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'text'</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">String</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-s1">'checked'</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-nb devsite-syntax-nb-Type">bool</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">checked</span><span class="devsite-syntax-p">}</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">CheckboxBlock</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">checked</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">_</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">throw</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">FormatException</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-s1">'Unexpected JSON format'</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">};</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <p>The <code translate="no" dir="ltr">sealed</code> keyword is a <em>class modifier</em> that means you can <em>only extend or implement this class in the same library</em>. Since the analyzer knows the subtypes of this class, it reports an error if a switch fails to cover one of them and isn't exhaustive.</p> <h2 is-upgraded id="use-a-switch-expression-in-order-to-display-widgets" data-text="Use a switch expression in order to display widgets" tabindex="-1">Use a switch expression in order to display widgets</h2> <ol type="1"> <li>Update the BlockWidget class in <code translate="no" dir="ltr">main.dart</code> with a switch expression that uses object patterns for each case:</li> </ol> <h3 is-upgraded id="libmain.dart_10" data-text="lib/main.dart" tabindex="-1"><a href="https://github.com/flutter/codelabs/blob/main/dart-patterns-and-records/step_12/lib/data.dart" target="_blank">lib/main.dart</a></h3> <div></div><devsite-code><pre class="devsite-click-to-copy" translate="no" dir="ltr" is-upgraded syntax="GDScript"><code translate="no" dir="ltr"><span class="devsite-syntax-k">class</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">BlockWidget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">extends</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">StatelessWidget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Block</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">block</span><span class="devsite-syntax-p">;</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">BlockWidget</span><span class="devsite-syntax-p">({</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">required</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">this</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">block</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">super</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">key</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">});</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-err">@</span><span class="devsite-syntax-n">override</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Widget</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">build</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">BuildContext</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">return</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Container</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">margin</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-k">const</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">EdgeInsets</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">all</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-mi">8</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">child</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">switch</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">block</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">HeaderBlock</span><span class="devsite-syntax-p">(:</span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">style</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Theme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">of</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">context</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">textTheme</span><span class="devsite-syntax-o">.</span><span class="devsite-syntax-n">displayMedium</span><span class="devsite-syntax-p">,</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">ParagraphBlock</span><span class="devsite-syntax-p">(:</span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">CheckboxBlock</span><span class="devsite-syntax-p">(:</span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-n">final</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">isChecked</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-o">=</span>><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Row</span><span class="devsite-syntax-p">(</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">children</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">[</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Checkbox</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">value</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">isChecked</span><span class="devsite-syntax-p">,</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">onChanged</span><span class="devsite-syntax-p">:</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">_</span><span class="devsite-syntax-p">)</span><span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">{}),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-n">Text</span><span class="devsite-syntax-p">(</span><span class="devsite-syntax-n">text</span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">],</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">),</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">},</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">);</span> <span class="devsite-syntax-w"> </span><span class="devsite-syntax-p">}</span> <span class="devsite-syntax-p">}</span> </code></pre></devsite-code> <p>In your first version of <code translate="no" dir="ltr">BlockWidget</code>, you switched on a field of a <code translate="no" dir="ltr">Block</code> object to return a <code translate="no" dir="ltr">TextStyle</code>. Now, you switch an instance of the <code translate="no" dir="ltr">Block</code> object itself and match against <em>object patterns</em> that represent its subclasses, extracting the object's properties in the process.</p> <p>The Dart analyzer can check that each subclass is handled in the switch expression because you made <code translate="no" dir="ltr">Block</code> a sealed class.</p> <aside class="warning"><p><strong>Try it out:</strong> Try removing one of the subclass cases from the switch expression and see the error kick in:</p> <p class="image-container"><img alt="A screenshot of a warning in VS Code that warns that not all cases are exhaustively checked." style="width: 610.00px" src="/static/codelabs/dart-patterns-records/img/369f15b19c3ad936.png" srcset="https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/369f15b19c3ad936_36.png 36w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/369f15b19c3ad936_48.png 48w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/369f15b19c3ad936_72.png 72w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/369f15b19c3ad936_96.png 96w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/369f15b19c3ad936_480.png 480w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/369f15b19c3ad936_720.png 720w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/369f15b19c3ad936_856.png 856w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/369f15b19c3ad936_960.png 960w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/369f15b19c3ad936_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/369f15b19c3ad936_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/369f15b19c3ad936_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> </aside> <p>Also note that using a switch expression here lets you pass the result directly to the <code translate="no" dir="ltr">child</code> element, as opposed to the separate return statement needed before.</p> <ol type="1" start="2"> <li>Hot reload to see the checkbox JSON data rendered for the first time:</li> </ol> <p class="image-container"><img alt="A screenshot of the app that displays the checkbox 'Learn Dart 3'" style="width: 624.00px" src="/static/codelabs/dart-patterns-records/img/5b9b4729bd65787d.png" srcset="https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5b9b4729bd65787d_36.png 36w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5b9b4729bd65787d_48.png 48w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5b9b4729bd65787d_72.png 72w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5b9b4729bd65787d_96.png 96w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5b9b4729bd65787d_480.png 480w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5b9b4729bd65787d_720.png 720w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5b9b4729bd65787d_856.png 856w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5b9b4729bd65787d_960.png 960w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5b9b4729bd65787d_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5b9b4729bd65787d_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/5b9b4729bd65787d_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <aside class="special"><p><strong>Try it out:</strong> Try changing the value of the <code translate="no" dir="ltr">checked</code> key in the <code translate="no" dir="ltr">Document</code> class, where you defined <code translate="no" dir="ltr">documentJson</code> to <code translate="no" dir="ltr">true</code> instead of <code translate="no" dir="ltr">false</code>. Hot reload again to see the UI update!</p> <p class="image-container"><img alt="A screenshot of the app that contains a checkbox 'Learn Dart 3' that is now checked." style="width: 610.00px" src="/static/codelabs/dart-patterns-records/img/f1f3c70ba4c04a64.png" srcset="https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/f1f3c70ba4c04a64_36.png 36w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/f1f3c70ba4c04a64_48.png 48w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/f1f3c70ba4c04a64_72.png 72w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/f1f3c70ba4c04a64_96.png 96w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/f1f3c70ba4c04a64_480.png 480w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/f1f3c70ba4c04a64_720.png 720w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/f1f3c70ba4c04a64_856.png 856w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/f1f3c70ba4c04a64_960.png 960w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/f1f3c70ba4c04a64_1440.png 1440w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/f1f3c70ba4c04a64_1920.png 1920w,https://codelabs.developers.google.com/static/codelabs/dart-patterns-records/img/f1f3c70ba4c04a64_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> </aside> </google-codelab-step> <google-codelab-step label="Congratulations" duration="0" step="12"> <h2 class="step-title" id="12" data-text="Congratulations" tabindex="-1"> 13. Congratulations </h2> <p>You successfully experimented with patterns, records, enhanced switch and case, and sealed classes. You covered a lot of information—but only barely scratched the surface of these features. For more information on patterns, see the <a href="https://github.com/dart-lang/language/blob/master/accepted/future-releases/0546-patterns/feature-specification.md" target="_blank">feature specification</a>.</p> <p>The different pattern types, different contexts in which they can appear, and the potential nesting of subpatterns make the possibilities in behavior seemingly <em>endless</em>. But they're easy to see.</p> <p>You can imagine all kinds of ways to display content in Flutter using patterns. Using patterns, you can safely extract data in order to build your UI in a few lines of code.</p> <h2 is-upgraded id="whats-next" data-text="What's next?" tabindex="-1"><strong>What's next?</strong></h2> <ul> <li>Check out the documentation on patterns, records, enhanced switch and cases, and class modifiers in the <a href="https://dart.dev/language" target="_blank">Language section</a> of the Dart documentation.</li> </ul> <h2 is-upgraded id="reference-docs" data-text="Reference docs" tabindex="-1"><strong>Reference docs</strong></h2> <p>See the full sample code, step by step, in the <a href="https://github.com/flutter/codelabs/tree/main/dart-patterns-and-records" target="_blank"><code translate="no" dir="ltr">flutter/codelabs</code> repository</a>.</p> <p>For in-depth specifications for each new feature, check out the original design docs:</p> <ul> <li><a href="https://github.com/dart-lang/language/blob/master/accepted/future-releases/0546-patterns/feature-specification.md" target="_blank">Patterns</a></li> <li><a href="https://github.com/dart-lang/language/blob/master/accepted/future-releases/records/records-feature-specification.md" target="_blank">Records</a></li> <li><a href="https://github.com/dart-lang/language/blob/master/accepted/future-releases/0546-patterns/exhaustiveness.md" target="_blank">Exhaustiveness checking</a></li> <li><a href="https://github.com/dart-lang/language/blob/master/accepted/future-releases/sealed-types/feature-specification.md" target="_blank">Sealed classes</a></li> </ul> </google-codelab-step> </google-codelab> </div> <div class="devsite-floating-action-buttons"> </div> </article> <devsite-content-footer class="nocontent"> <p>Except as otherwise noted, the content of this page is licensed under the <a href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 License</a>, and code samples are licensed under the <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache 2.0 License</a>. For details, see the <a href="https://developers.google.com/site-policies">Google Developers Site Policies</a>. Java is a registered trademark of Oracle and/or its affiliates.</p> </devsite-content-footer> <devsite-notification > </devsite-notification> <div class="devsite-content-data"> <template class="devsite-content-data-template"> [[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],[],[],[]] </template> </div> </devsite-content> </main> <devsite-footer-promos class="devsite-footer"> </devsite-footer-promos> <devsite-footer-linkboxes class="devsite-footer"> <nav class="devsite-footer-linkboxes nocontent" aria-label="Footer links"> <ul class="devsite-footer-linkboxes-list"> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">Connect</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="//googledevelopers.blogspot.com" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)" > Blog </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//www.facebook.com/Google-Developers-967415219957038" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)" > Facebook </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//medium.com/google-developers" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 3)" > Medium </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//twitter.com/googledevs" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 4)" > Twitter </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//www.youtube.com/user/GoogleDevelopers" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 5)" > YouTube </a> </li> </ul> </li> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">Programs</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="//www.womentechmakers.com" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)" > Women Techmakers </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//developers.google.com/community/gdg" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)" > Google Developer Groups </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//developers.google.com/community/experts" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 3)" > Google Developer Experts </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//developers.google.com/community/accelerators" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 4)" > Accelerators </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//developers.google.com/community/gdsc" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 5)" > Google Developer Student Clubs </a> </li> </ul> </li> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">Developer consoles</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="//console.developers.google.com" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)" > Google API Console </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//console.cloud.google.com" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)" > Google Cloud Platform Console </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//play.google.com/apps/publish" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 3)" > Google Play Console </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//console.firebase.google.com" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 4)" > Firebase Console </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//console.actions.google.com" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 5)" > Actions on Google Console </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//cast.google.com/publish" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 6)" > Cast SDK Developer Console </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//chrome.google.com/webstore/developer/dashboard" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 7)" > Chrome Web Store Dashboard </a> </li> </ul> </li> </ul> </nav> </devsite-footer-linkboxes> <devsite-footer-utility class="devsite-footer"> <div class="devsite-footer-utility nocontent"> <nav class="devsite-footer-sites" aria-label="Other Google Developers websites"> <a href="https://developers.google.com/" class="devsite-footer-sites-logo-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Google Developers Link"> <picture> <img class="devsite-footer-sites-logo" src="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/codelabs/images/lockup-google-for-developers.svg" loading="lazy" alt="Google Developers"> </picture> </a> <ul class="devsite-footer-sites-list"> <li class="devsite-footer-sites-item"> <a href="//developer.android.com" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Android Link" > Android </a> </li> <li class="devsite-footer-sites-item"> <a href="//developer.chrome.com/home" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Chrome Link" > Chrome </a> </li> <li class="devsite-footer-sites-item"> <a href="//firebase.google.com" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Firebase Link" > Firebase </a> </li> <li class="devsite-footer-sites-item"> <a href="//cloud.google.com" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Google Cloud Platform Link" > Google Cloud Platform </a> </li> <li class="devsite-footer-sites-item"> <a href="//developers.google.com/products" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer All products Link" > All products </a> </li> </ul> </nav> <nav class="devsite-footer-utility-links" aria-label="Utility links"> <ul class="devsite-footer-utility-list"> <li class="devsite-footer-utility-item "> <a class="devsite-footer-utility-link gc-analytics-event" href="//developers.google.com/terms/site-terms" data-category="Site-Wide Custom Events" data-label="Footer Terms link" > Terms </a> </li> <li class="devsite-footer-utility-item "> <a class="devsite-footer-utility-link gc-analytics-event" href="//policies.google.com/privacy" data-category="Site-Wide Custom Events" data-label="Footer Privacy link" > Privacy </a> </li> <li class="devsite-footer-utility-item glue-cookie-notification-bar-control"> <a class="devsite-footer-utility-link gc-analytics-event" href="#" data-category="Site-Wide Custom Events" data-label="Footer Manage cookies link" aria-hidden="true" > Manage cookies </a> </li> <li class="devsite-footer-utility-item devsite-footer-utility-button"> <span class="devsite-footer-utility-description">Sign up for the Google Developers newsletter</span> <a class="devsite-footer-utility-link gc-analytics-event" href="//services.google.com/fb/forms/googledevelopersnewsletter/?utm_medium=referral&utm_source=google-products&utm_team=googledevs&utm_campaign=201611-newsletter-launch" data-category="Site-Wide Custom Events" data-label="Footer Subscribe link" > Subscribe </a> </li> </ul> <devsite-language-selector> <ul role="presentation"> <li role="presentation"> <a role="menuitem" lang="en" >English</a> </li> <li role="presentation"> <a role="menuitem" lang="de" >Deutsch</a> </li> <li role="presentation"> <a role="menuitem" lang="es" >Español</a> </li> <li role="presentation"> <a role="menuitem" lang="es_419" >Español – América Latina</a> </li> <li role="presentation"> <a role="menuitem" lang="fr" >Français</a> </li> <li role="presentation"> <a role="menuitem" lang="id" >Indonesia</a> </li> <li role="presentation"> <a role="menuitem" lang="it" >Italiano</a> </li> <li role="presentation"> <a role="menuitem" lang="pl" >Polski</a> </li> <li role="presentation"> <a role="menuitem" lang="pt_br" >Português – Brasil</a> </li> <li role="presentation"> <a role="menuitem" lang="vi" >Tiếng Việt</a> </li> <li role="presentation"> <a role="menuitem" lang="tr" >Türkçe</a> </li> <li role="presentation"> <a role="menuitem" lang="ru" >Русский</a> </li> <li role="presentation"> <a role="menuitem" lang="he" >עברית</a> </li> <li role="presentation"> <a role="menuitem" lang="ar" >العربيّة</a> </li> <li role="presentation"> <a role="menuitem" lang="fa" >فارسی</a> </li> <li role="presentation"> <a role="menuitem" lang="hi" >हिंदी</a> </li> <li role="presentation"> <a role="menuitem" lang="bn" >বাংলা</a> </li> <li role="presentation"> <a role="menuitem" lang="th" >ภาษาไทย</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_cn" >中文 – 简体</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_tw" >中文 – 繁體</a> </li> <li role="presentation"> <a role="menuitem" lang="ja" >日本語</a> </li> <li role="presentation"> <a role="menuitem" lang="ko" >한국어</a> </li> </ul> </devsite-language-selector> </nav> </div> </devsite-footer-utility> <devsite-panel></devsite-panel> </section></section> <devsite-sitemask></devsite-sitemask> <devsite-snackbar></devsite-snackbar> <devsite-tooltip ></devsite-tooltip> <devsite-heading-link></devsite-heading-link> <devsite-analytics> <script type="application/json" analytics>[]</script> <script type="application/json" tag-management>{"at": "True", "ga4": [], "ga4p": [], "gtm": [], "parameters": {"internalUser": "False", "language": {"machineTranslated": "False", "requested": "en", "served": "en"}, "pageType": "codelab", "projectName": null, "signedIn": "False", "tenant": "codelabs", "recommendations": {"sourcePage": "", "sourceType": 0, "sourceRank": 0, "sourceIdenticalDescriptions": 0, "sourceTitleWords": 0, "sourceDescriptionWords": 0, "experiment": ""}, "experiment": {"ids": ""}}}</script> </devsite-analytics> <devsite-badger></devsite-badger> <script nonce="MxqlPWYYM25UwSytJ+C6sm5XSOu/nE"> (function(d,e,v,s,i,t,E){d['GoogleDevelopersObject']=i; t=e.createElement(v);t.async=1;t.src=s;E=e.getElementsByTagName(v)[0]; E.parentNode.insertBefore(t,E);})(window, document, 'script', 'https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/codelabs/js/app_loader.js', '[17,"en",null,"/js/devsite_app_module.js","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/codelabs","https://codelabs-dot-devsite-v2-prod.appspot.com",1,null,["/_pwa/codelabs/manifest.json","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/images/video-placeholder.svg","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/codelabs/images/favicon.png","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/codelabs/images/lockup.svg","https://fonts.googleapis.com/css?family=Google+Sans:400,500|Roboto:400,400italic,500,500italic,700,700italic|Roboto+Mono:400,500,700&display=swap"],1,null,[1,6,8,12,14,17,21,25,50,52,63,70,75,76,80,87,91,92,93,97,98,100,101,102,103,104,105,107,108,109,110,112,113,117,118,120,122,124,125,126,127,129,130,131,132,133,134,135,136,138,140,141,147,148,149,151,152,156,157,158,159,161,163,164,168,169,170,179,180,182,183,186,191,193,196],"AIzaSyAP-jjEJBzmIyKR4F-3XITp8yM9T1gEEI8","AIzaSyB6xiKGDR5O3Ak2okS4rLkauxGUG7XP0hg","codelabs.developers.google.com","AIzaSyAQk0fBONSGUqCNznf6Krs82Ap1-NV6J4o","AIzaSyCCxcqdrZ_7QMeLCRY20bh_SXdAYqy70KY",null,null,null,["TpcFeatures__enable_mirror_tenant_redirects","Profiles__enable_awarding_url","Profiles__enable_complete_playlist_endpoint","DevPro__enable_developer_subscriptions","MiscFeatureFlags__enable_variable_operator","CloudShell__cloud_shell_button","TpcFeatures__enable_required_headers","Profiles__enable_recognition_badges","Cloud__enable_cloud_dlp_service","MiscFeatureFlags__developers_footer_dark_image","Cloud__enable_cloudx_experiment_ids","Profiles__enable_release_notes_notifications","Concierge__enable_pushui","Search__enable_page_map","MiscFeatureFlags__enable_view_transitions","EngEduTelemetry__enable_engedu_telemetry","CloudShell__cloud_code_overflow_menu","Cloud__enable_cloudx_ping","Profiles__enable_public_developer_profiles","MiscFeatureFlags__emergency_css","Profiles__enable_dashboard_curated_recommendations","MiscFeatureFlags__developers_footer_image","Search__enable_suggestions_from_borg","Cloud__enable_cloud_facet_chat","Profiles__enable_page_saving","MiscFeatureFlags__enable_project_variables","Cloud__enable_legacy_calculator_redirect","Search__enable_dynamic_content_confidential_banner","Search__enable_ai_eligibility_checks","MiscFeatureFlags__enable_explain_this_code","Cloud__enable_cloud_shell","MiscFeatureFlags__enable_firebase_utm","Cloud__enable_llm_concierge_chat","Experiments__reqs_query_experiments","Profiles__require_profile_eligibility_for_signin","DevPro__enable_cloud_innovators_plus","Profiles__enable_completecodelab_endpoint","Profiles__enable_profile_collections","BookNav__enable_tenant_cache_key","Cloud__enable_free_trial_server_call","Analytics__enable_clearcut_logging","Profiles__enable_developer_profiles_callout","Cloud__enable_cloud_shell_fte_user_flow"],null,null,"AIzaSyBLEMok-5suZ67qRPzx0qUtbnLmyT_kCVE","https://developerscontentserving-pa.clients6.google.com","AIzaSyCM4QpTRSqP5qI4Dvjt4OAScIN8sOUlO-k","https://developerscontentsearch-pa.clients6.google.com",1,4,null,"https://developerprofiles-pa.clients6.google.com",[17,"codelabs","Google Codelabs","codelabs.developers.google.com",null,"codelabs-dot-devsite-v2-prod.appspot.com",null,null,[null,1,null,null,null,null,null,null,null,null,null,[1],null,null,null,null,null,null,[1],null,null,null,null,[1]],null,[33,null,null,null,null,null,"/images/lockup.svg",null,null,null,null,1,1,null,null,null,null,null,null,null,null,1,null,null,null,null,[]],[],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[6,1,14,15,20,22,23,29,32,36],null,[[],[1,1]],[[null,null,null,null,null,null,null,null,null,null,null,null,1]],null,4],null,"pk_live_5170syrHvgGVmSx9sBrnWtA5luvk9BwnVcvIi7HizpwauFG96WedXsuXh790rtij9AmGllqPtMLfhe2RSwD6Pn38V00uBCydV4m"]') </script> <devsite-a11y-announce></devsite-a11y-announce> </body> </html>