Dart के पैटर्न और रिकॉर्ड के बारे में ज़्यादा जानें

1. परिचय

Dart 3 भाषा के लिए पैटर्न पेश करता है, जो व्याकरण की एक नई श्रेणी है. Dart कोड लिखने के इस नए तरीके के अलावा, अन्य कई भाषाएँ बेहतर हैं जिनमें ये शामिल हैं

  • अलग-अलग तरह के डेटा का बंडल बनाने के लिए रिकॉर्ड,
  • क्लास मॉडिफ़ायर का इस्तेमाल करके ऐक्सेस कंट्रोल कर सकते हैं और
  • नए स्विच एक्सप्रेशन और if-case स्टेटमेंट होंगे.

इन सुविधाओं से, Dart कोड लिखने के दौरान मिलने वाले विकल्पों में ज़्यादा विकल्प मिलते हैं. इस कोडलैब में, आपको अपने कोड को ज़्यादा कॉम्पैक्ट, व्यवस्थित, और सुविधाजनक बनाने के लिए, उनके इस्तेमाल का तरीका पता चलेगा.

यह कोडलैब यह मानकर चलता है कि आपको Flutter और Dart के बारे में जानकारी है. अगर आपको थोड़ी जंग लग रही है, तो इन संसाधनों की मदद से बुनियादी चीज़ों को ठीक करने के बारे में सोचें:

आपको क्या बनाना होगा

यह कोडलैब एक ऐसा ऐप्लिकेशन बनाता है जो Flutter में JSON दस्तावेज़ दिखाता है. यह ऐप्लिकेशन, किसी बाहरी सोर्स से आने वाले JSON को सिम्युलेट करता है. JSON में, दस्तावेज़ का डेटा मौजूद होता है. जैसे, बदलाव की तारीख, टाइटल, हेडर, और पैराग्राफ़. रिकॉर्ड में सही तरीके से डेटा पैक करने के लिए कोड लिखे जाते हैं, ताकि आपके Flutter विजेट की ज़रूरत पड़ने पर उन्हें ट्रांसफ़र और अनपैक किया जा सके.

इसके बाद, वैल्यू के उस पैटर्न से मेल खाने पर, सही विजेट बनाने के लिए पैटर्न का इस्तेमाल किया जाता है. साथ ही, यह भी देखा जा सकता है कि लोकल वैरिएबल में डेटा को व्यवस्थित करने के लिए, पैटर्न का इस्तेमाल कैसे किया जाता है.

इस कोडलैब में आपका बनाया जाने वाला आखिरी ऐप्लिकेशन, एक शीर्षक वाला दस्तावेज़, पिछली बार बदलाव करने की तारीख, हेडर और पैराग्राफ़.

आपको इनके बारे में जानकारी मिलेगी

  • ऐसा रिकॉर्ड कैसे बनाएं जिसमें अलग-अलग टाइप के लिए एक से ज़्यादा वैल्यू सेव की गई हों.
  • रिकॉर्ड का इस्तेमाल करके, किसी फ़ंक्शन से एक से ज़्यादा वैल्यू पाने का तरीका.
  • रिकॉर्ड और अन्य ऑब्जेक्ट से डेटा का मिलान करने, उसकी पुष्टि करने, और उसे अलग करने के लिए, पैटर्न का इस्तेमाल कैसे करें.
  • पैटर्न से मेल खाने वाली वैल्यू को नए या मौजूदा वैरिएबल से बाइंड करने का तरीका.
  • नई स्विच स्टेटमेंट क्षमताओं, स्विच एक्सप्रेशन, और 'अगर-केस स्टेटमेंट' का इस्तेमाल करने का तरीका जानें.
  • यह पक्का करने के लिए कि हर मामले को स्विच स्टेटमेंट या स्विच एक्सप्रेशन में हैंडल किया जाता हो, पूरी जानकारी की जांच करने की सुविधा का फ़ायदा लें.

2. अपना एनवायरमेंट सेट अप करें

  1. Flutter SDK टूल इंस्टॉल करें.
  2. विज़ुअल स्टूडियो कोड (वीएस कोड) जैसा एडिटर सेट अप करें.
  3. कम से कम एक टारगेट प्लैटफ़ॉर्म (iOS, Android, डेस्कटॉप या वेब ब्राउज़र) के लिए, प्लैटफ़ॉर्म सेटअप करने का तरीका देखें.

3. प्रोजेक्ट बनाएं

पैटर्न, रिकॉर्ड, और अन्य नई सुविधाओं के बारे में जानने से पहले, कुछ समय निकालकर एक ऐसा आसान Flutter प्रोजेक्ट बनाएं जिसके लिए आपको अपना पूरा कोड लिखना होगा.

Flutter प्रोजेक्ट बनाना

  1. patterns_codelab नाम का नया प्रोजेक्ट बनाने के लिए, flutter create कमांड का इस्तेमाल करें. --empty फ़्लैग lib/main.dart फ़ाइल में स्टैंडर्ड काउंटर ऐप्लिकेशन बनाने से रोकता है जिसे आपको फिर भी हटाना होगा.
flutter create --empty patterns_codelab
  1. इसके बाद, वीएस कोड का इस्तेमाल करके patterns_codelab डायरेक्ट्री खोलें.
code patterns_codelab

वीएस कोड का स्क्रीनशॉट, जिसमें 'फ़्लटर बनाएं' की मदद से बनाया गया प्रोजेक्ट दिखाया गया हो आदेश.

SDK टूल का कम से कम वर्शन सेट करना

  • अपने प्रोजेक्ट के लिए SDK के वर्शन का कंस्ट्रेंट सेट करें, ताकि यह Dart 3 या उसके बाद के वर्शन का इस्तेमाल कर सके.

pubspec.yaml

environment:
  sdk: ^3.0.0

4. प्रोजेक्ट सेट अप करना

इस चरण में, दो Dart फ़ाइलें बनाई या अपडेट की जा सकती हैं:

  • main.dart फ़ाइल जिसमें ऐप्लिकेशन के विजेट हैं और
  • ऐप्लिकेशन का डेटा उपलब्ध कराने वाली data.dart फ़ाइल.

बाद के चरणों में आप इन दोनों फ़ाइलों में बदलाव करना जारी रखेंगे.

ऐप्लिकेशन का डेटा तय करना

  • lib/data.dart के नाम से एक नई फ़ाइल बनाएं और उसमें यह कोड जोड़ें:

lib/data.dart

import 'dart:convert';

class Document {
  final Map<String, Object?> _json;
  Document() : _json = jsonDecode(documentJson);
}

const documentJson = '''
{
  "metadata": {
    "title": "My Document",
    "modified": "2023-05-10"
  },
  "blocks": [
    {
      "type": "h1",
      "text": "Chapter 1"
    },
    {
      "type": "p",
      "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
    },
    {
      "type": "checkbox",
      "checked": false,
      "text": "Learn Dart 3"
    }
  ]
}
''';

कल्पना करें कि किसी प्रोग्राम को किसी बाहरी सोर्स से डेटा मिल रहा है, जैसे कि I/O स्ट्रीम या एचटीटीपी अनुरोध. इस कोडलैब में, documentJson वैरिएबल में एक से ज़्यादा लाइन वाली स्ट्रिंग की मदद से, आने वाले JSON डेटा का मज़ाक़ बनाया जा रहा है. इससे इस्तेमाल के उदाहरण को आसान बनाया जा सकता है.

JSON डेटा, Document क्लास में तय किया जाता है. इस कोडलैब में आगे ऐसे फ़ंक्शन जोड़े जा सकते हैं जो पार्स किए गए JSON से डेटा दिखाते हैं. यह क्लास अपने कंस्ट्रक्टर में, _json फ़ील्ड के बारे में बताती है और उसे शुरू करती है.

ऐप्लिकेशन चलाएं

flutter create निर्देश, डिफ़ॉल्ट Flutter फ़ाइल स्ट्रक्चर के हिस्से के तौर पर lib/main.dart फ़ाइल बनाता है.

  1. ऐप्लिकेशन के लिए शुरुआती पॉइंट बनाने के लिए, main.dart की सामग्री को नीचे दिए गए कोड से बदलें:

lib/main.dart

import 'package:flutter/material.dart';

import 'data.dart';

void main() {
  runApp(const DocumentApp());
}

class DocumentApp extends StatelessWidget {
  const DocumentApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(useMaterial3: true),
      home: DocumentScreen(
        document: Document(),
      ),
    );
  }
}

class DocumentScreen extends StatelessWidget {
  final Document document;

  const DocumentScreen({
    required this.document,
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Title goes here'),
      ),
      body: const Column(
        children: [
          Center(
            child: Text('Body goes here'),
          ),
        ],
      ),
    );
  }
}

आपने ऐप्लिकेशन में ये दो विजेट जोड़े हैं:

  • DocumentApp, यूज़र इंटरफ़ेस (यूआई) की थीम के लिए, मटीरियल डिज़ाइन का सबसे नया वर्शन सेट अप करता है.
  • DocumentScreen, Scaffold विजेट का इस्तेमाल करके, पेज का विज़ुअल लेआउट उपलब्ध कराता है.
  1. यह पक्का करने के लिए कि सब कुछ ठीक से चल रहा है, चलाएं और डीबग करें पर क्लिक करके अपनी होस्ट मशीन पर ऐप्लिकेशन चलाएं:

&#39;Run और डीबग&#39; बटन की इमेज बटन, &#39;रन और डीबग करें&#39; में उपलब्ध है सेक्शन पर क्लिक करें.

  1. डिफ़ॉल्ट रूप से, Flutter वह टारगेट प्लैटफ़ॉर्म चुनता है जो उपलब्ध हो. टारगेट प्लैटफ़ॉर्म बदलने के लिए, स्टेटस बार में मौजूदा प्लैटफ़ॉर्म चुनें:

बनाम कोड में टारगेट प्लैटफ़ॉर्म सिलेक्टर का स्क्रीनशॉट.

आपको DocumentScreen विजेट में तय किए गए title और body एलिमेंट वाला एक खाली फ़्रेम दिखेगा:

इस चरण में बनाए गए ऐप्लिकेशन का स्क्रीनशॉट.

5. रिकॉर्ड बनाएं और वापस करें

इस चरण में, रिकॉर्ड का इस्तेमाल करके किसी फ़ंक्शन कॉल से कई वैल्यू दिखाई जाती हैं. इसके बाद, उस फ़ंक्शन को DocumentScreen विजेट में कॉल किया जा सकता है, ताकि वैल्यू को ऐक्सेस किया जा सके और उन्हें यूज़र इंटरफ़ेस (यूआई) में दिखाया जा सके.

रिकॉर्ड बनाना और उसे वापस करना

  • data.dart में, दस्तावेज़ की क्लास में metadata नाम का एक नया गैटर तरीका जोड़ें. इससे रिकॉर्ड दिखाया जाता है:

lib/data.dart

import 'dart:convert';

class Document {
  final Map<String, Object?> _json;
  Document() : _json = jsonDecode(documentJson);

  (String, {DateTime modified}) get metadata {           // Add from here...
    const title = 'My Document';
    final now = DateTime.now();

    return (title, modified: now);
  }                                                      // to here.
}

इस फ़ंक्शन के लिए रिटर्न टाइप एक रिकॉर्ड है, जिसमें दो फ़ील्ड होते हैं, एक फ़ील्ड String और दूसरा DateTime.

यह रिटर्न स्टेटमेंट, दोनों वैल्यू को ब्रैकेट (title, modified: now) में बंद करके एक नया रिकॉर्ड बनाता है.

पहला फ़ील्ड पोज़िशनल और बिना नाम वाला फ़ील्ड होता है. दूसरे फ़ील्ड का नाम modified होता है.

रिकॉर्ड फ़ील्ड ऐक्सेस करना

  1. DocumentScreen विजेट में, build तरीके में metadata गैटर तरीके को कॉल करें, ताकि आप अपना रिकॉर्ड पा सकें और उसकी वैल्यू ऐक्सेस कर सकें:

lib/main.dart

class DocumentScreen extends StatelessWidget {
  final Document document;

  const DocumentScreen({
    required this.document,
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    final metadataRecord = document.metadata;              // Add this line.

    return Scaffold(
      appBar: AppBar(
        title: Text(metadataRecord.$1),                    // Modify this line,
      ),
      body: Column(
        children: [
          Center(
            child: Text(
              'Last modified ${metadataRecord.modified}',  // And this one.
            ),
          ),
        ],
      ),
    );
  }
}

metadata गेटर तरीका, एक रिकॉर्ड दिखाता है, जिसे लोकल वैरिएबल metadataRecord को असाइन किया जाता है. रिकॉर्ड, एक ही फ़ंक्शन कॉल से कई वैल्यू देने और उन्हें किसी वैरिएबल पर असाइन करने का आसान और आसान तरीका है.

उस रिकॉर्ड में बनाए गए अलग-अलग फ़ील्ड को ऐक्सेस करने के लिए, 'रिकॉर्ड' का इस्तेमाल करें बिल्ट-इन गेटर सिंटैक्स.

  • पोज़िशनल फ़ील्ड (बिना नाम वाला फ़ील्ड, जैसे कि title) पाने के लिए, रिकॉर्ड पर गैटर $<num> का इस्तेमाल करें. यह सिर्फ़ बिना नाम वाले फ़ील्ड दिखाता है.
  • modified जैसे नाम वाले फ़ील्ड में पोज़िशनल गैटर नहीं होता. इसलिए, सीधे तौर पर इसके नाम का इस्तेमाल किया जा सकता है, जैसे कि metadataRecord.modified.

पोज़िशनल फ़ील्ड के लिए गैटर का नाम तय करने के लिए, $1 से शुरू करें और नाम वाले फ़ील्ड छोड़ें. उदाहरण के लिए:

var record = (named: 'v', 'y', named2: 'x', 'z');
print(record.$1);                               // prints y
print(record.$2);                               // prints z
  1. ऐप्लिकेशन में दिख रही JSON वैल्यू देखने के लिए, पेज को फिर से लोड करें. जब भी आप कोई फ़ाइल सेव करते हैं, तो वीएस कोड डार्ट प्लगिन हॉट-रीलोड हो जाता है.

ऐप्लिकेशन का स्क्रीनशॉट, जिसमें टाइटल और बदलाव करने की तारीख दिख रही है.

आप देख सकते हैं कि हर फ़ील्ड ने असल में अपना टाइप बनाए रखा है.

  • Text() तरीका, स्ट्रिंग को पहले तर्क के तौर पर लेता है.
  • modified फ़ील्ड, DateTime है. इसे स्ट्रिंग इंटरपोलेशन का इस्तेमाल करके, String में बदला जाता है.

अलग-अलग तरह का डेटा वापस करने का दूसरा सुरक्षित तरीका है क्लास तय करना, जो ज़्यादा शब्दों में जानकारी देती है.

6. पैटर्न की मदद से मिलान करना और व्यवस्थित करना

रिकॉर्ड, अलग-अलग तरह के डेटा को बेहतर तरीके से इकट्ठा कर सकते हैं और उन्हें आसानी से पास कर सकते हैं. अब, पैटर्न का इस्तेमाल करके अपने कोड को बेहतर बनाएं.

पैटर्न ऐसा स्ट्रक्चर दिखाता है जिसमें एक या उससे ज़्यादा वैल्यू हो सकती हैं, जैसे कि ब्लूप्रिंट. पैटर्न की तुलना असल वैल्यू से की जाती है, ताकि यह पता लगाया जा सके कि वे मिलते-जुलते हैं या नहीं.

कुछ पैटर्न मैच होने पर, मैच होने वाली वैल्यू को डिस्ट्रक्चर करने के लिए, डेटा को उससे अलग कर देते हैं. डिस्ट्रक्चर करने की सुविधा से, किसी ऑब्जेक्ट की वैल्यू को अनपैक किया जा सकता है. ऐसा करके, उन्हें लोकल वैरिएबल के लिए असाइन किया जा सकता है या उन वैल्यू को मैच किया जा सकता है.

किसी रिकॉर्ड को लोकल वैरिएबल के हिसाब से बनाना

  1. metadata को कॉल करने के लिए, DocumentScreen के build तरीके को फिर से तय करें. साथ ही, पैटर्न वैरिएबल का एलान शुरू करने के लिए इसका इस्तेमाल करें:

lib/main.dart

class DocumentScreen extends StatelessWidget {
  final Document document;

  const DocumentScreen({
    required this.document,
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    final (title, modified: modified) = document.metadata;   // Modify

    return Scaffold(
      appBar: AppBar(
        title: Text(title),                                  // Modify
      ),
      body: Column(
        children: [
          Center(
            child: Text(
              'Last modified $modified',                     // Modify
            ),
          ),
        ],
      ),
    );
  }
}

रिकॉर्ड पैटर्न (title, modified: modified) में दो वैरिएबल पैटर्न होते हैं. ये पैटर्न, metadata से लौटाए गए रिकॉर्ड के फ़ील्ड से मेल खाते हैं.

  • यह एक्सप्रेशन सबपैटर्न से मैच करता है, क्योंकि नतीजा दो फ़ील्ड वाला रिकॉर्ड है. इनमें से एक फ़ील्ड का नाम modified है.
  • इन दोनों के मैच होने की वजह से, वैरिएबल के एलान वाला पैटर्न, एक्सप्रेशन को डीस्ट्रक्चर करता है. साथ ही, इसकी वैल्यू ऐक्सेस करता है और उन्हें एक ही टाइप और नाम String title और DateTime modified वाले नए लोकल वैरिएबल से बाइंड करता है.

किसी फ़ील्ड का नाम और उसमें जानकारी डालने वाला वैरिएबल एक जैसा होने पर, इसका एक छोटा सा नाम लिया जा सकता है. DocumentScreen में से build तरीके को इस तरह से रीफ़ैक्टर करें.

lib/main.dart

class DocumentScreen extends StatelessWidget {
  final Document document;

  const DocumentScreen({
    required this.document,
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    final (title, :modified) = document.metadata;            // Modify

    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Column(
        children: [
          Center(
            child: Text(
              'Last modified $modified',
            ),
          ),
        ],
      ),
    );
  }
}

वैरिएबल पैटर्न :modified का सिंटैक्स modified: modified का शॉर्टहैंड है. अगर आपको किसी अलग नाम का नया लोकल वैरिएबल चाहिए, तो इसके बजाय modified: localModified लिखें.

  1. पिछले चरण जैसा नतीजा देखने के लिए, फिर से लोड करें. काम करने के तरीके में कोई बदलाव नहीं होता है; आपने अपने कोड को और छोटा बनाया है.

7. डेटा एक्सट्रैक्ट करने के लिए पैटर्न का इस्तेमाल करना

कुछ कॉन्टेक्स्ट में, पैटर्न सिर्फ़ मैच नहीं करते और उसे डीस्ट्रक्चर नहीं करते, बल्कि इस बारे में फ़ैसला भी ले सकते हैं कि कोड क्या काम करता है. यह इस बात पर निर्भर करता है कि पैटर्न मैच करता है या नहीं. इन्हें रीफ़्यूटेबल पैटर्न कहा जाता है.

आपने पिछले चरण में, वैरिएबल की जानकारी देने वाले जिस पैटर्न का इस्तेमाल किया है वह ऐसा पैटर्न है जिसे पूरा नहीं किया जा सकता: वैल्यू, पैटर्न से मैच होनी चाहिए. ऐसा न होने पर, कोई गड़बड़ी होगी और वह पैटर्न कभी नहीं बनेगा. किसी भी तरह के वैरिएबल एलान या असाइनमेंट के बारे में सोचें; अगर किसी वैरिएबल का टाइप एक जैसा नहीं है, तो उसके लिए कोई वैल्यू असाइन नहीं की जा सकती.

दूसरी ओर, रेफ़र करने लायक पैटर्न का इस्तेमाल कंट्रोल फ़्लो के कॉन्टेक्स्ट में किया जाता है:

  • वे उम्मीद करते हैं कि वे कुछ वैल्यू जिनकी तुलना में करेंगे, वे मेल नहीं खाएंगी.
  • वैल्यू इस हिसाब से तय की जाती हैं कि कंट्रोल फ़्लो पर असर डालें या वैल्यू मेल खाती है या नहीं.
  • अगर इन दोनों के आपस में मेल नहीं खाते, तो गड़बड़ी की वजह से एज़ीक्यूशन में कोई रुकावट नहीं आती. ऐसा होने पर, अगले स्टेटमेंट पर क्लिक हो जाता है.
  • वे वैरिएबल को डिस्ट्रक्चर और बाइंड कर सकते हैं जो मैच करने पर सिर्फ़ इस्तेमाल किए जा सकते हैं

पैटर्न के बिना JSON की वैल्यू पढ़ना

इस सेक्शन में, पैटर्न मैचिंग के बिना डेटा पढ़ा जाता है. इससे आपको पता चलता है कि पैटर्न, JSON डेटा के साथ काम करने में कैसे मदद कर सकते हैं.

  • metadata के पिछले वर्शन को ऐसे वर्शन से बदलें जो _json मैप में दी गई वैल्यू को पढ़ता हो. metadata के इस वर्शन को कॉपी करके Document क्लास में चिपकाएं:

lib/data.dart

class Document {
  final Map<String, Object?> _json;
  Document() : _json = jsonDecode(documentJson);

  (String, {DateTime modified}) get metadata {
    if (_json.containsKey('metadata')) {                     // Modify from here...
      final metadataJson = _json['metadata'];
      if (metadataJson is Map) {
        final title = metadataJson['title'] as String;
        final localModified =
            DateTime.parse(metadataJson['modified'] as String);
        return (title, modified: localModified);
      }
    }
    throw const FormatException('Unexpected JSON');          // to here.
  }
}

इस कोड से इस बात की पुष्टि होती है कि डेटा को सही तरीके से स्ट्रक्चर किया गया है और पैटर्न का इस्तेमाल नहीं किया गया है. बाद के चरण में, कम कोड का इस्तेमाल करके पुष्टि करने के लिए पैटर्न मैचिंग का इस्तेमाल किया जाता है. कुछ भी करने से पहले यह तीन जांच करता है:

  • JSON में वह डेटा स्ट्रक्चर शामिल है जिसकी आपको उम्मीद है: if (_json.containsKey('metadata'))
  • डेटा में वह टाइप है जिसकी आपको उम्मीद है: if (metadataJson is Map)
  • यह डेटा शून्य नहीं है, इसकी पुष्टि पिछली जांच में की गई थी.

मैप पैटर्न का इस्तेमाल करके, JSON फ़ॉर्मैट की वैल्यू पढ़ना

नए पैटर्न की मदद से, मैप पैटर्न का इस्तेमाल करके, पुष्टि की जा सकती है कि JSON का स्ट्रक्चर सही है या नहीं.

  • metadata के पिछले वर्शन को इस कोड से बदलें:

lib/data.dart

class Document {
  final Map<String, Object?> _json;
  Document() : _json = jsonDecode(documentJson);

  (String, {DateTime modified}) get metadata {
    if (_json                                                // Modify from here...
        case {
          'metadata': {
            'title': String title,
            'modified': String localModified,
          }
        }) {
      return (title, modified: DateTime.parse(localModified));
    } else {
      throw const FormatException('Unexpected JSON');
    }                                                        // to here.
  }
}

यहां, आपको एक नए तरह का if-स्टेटमेंट (Drt 3 में पेश किया गया), if-case दिखता है. केस का मुख्य हिस्सा सिर्फ़ तब काम करता है, जब केस पैटर्न, _json के डेटा से मेल खाता हो. इस मैच में वही जांच पूरी होती हैं जो आपने metadata के पहले वर्शन में लिखी थीं, ताकि इनकमिंग JSON की पुष्टि की जा सके. यह कोड इन चीज़ों की पुष्टि करता है:

  • _json एक तरह का मैप है.
  • _json में एक metadata कुंजी है.
  • _json खाली नहीं है.
  • _json['metadata'] भी एक मैप टाइप है.
  • _json['metadata'] में title और modified कुंजियां हैं.
  • title और localModified स्ट्रिंग हैं और अमान्य नहीं हैं.

अगर वैल्यू मेल नहीं खाती है, तो पैटर्न अस्वीकार किया जाता है (परफ़ॉर्मेंस की प्रोसेस जारी रखने से मना किया जाता है) और else क्लॉज़ पर आगे बढ़ जाता है. अगर मैच हो जाता है, तो पैटर्न, मैप से title और modified की वैल्यू को अलग कर देता है और उन्हें नए लोकल वैरिएबल से बाइंड कर देता है.

पैटर्न की पूरी सूची देखने के लिए, सुविधा की खास बातों में पैटर्न सेक्शन में दी गई टेबल देखें.

8. ज़्यादा पैटर्न के लिए ऐप्लिकेशन तैयार करें

अब तक, आपने JSON डेटा के metadata वाले हिस्से के बारे में जानकारी दी है. इस चरण में, blocks सूची में मौजूद डेटा को मैनेज करने और उसे अपने ऐप्लिकेशन में रेंडर करने के लिए, अपने कारोबार के लॉजिक को थोड़ा और बेहतर बनाया जाता है.

{
  "metadata": {
    // ...
  },
  "blocks": [
    {
      "type": "h1",
      "text": "Chapter 1"
    },
    // ...
  ]
}

डेटा स्टोर करने वाली क्लास बनाएं

  • data.dart में एक नई क्लास Block जोड़ें, जिसका इस्तेमाल JSON डेटा में मौजूद किसी एक ब्लॉक के डेटा को पढ़ने और सेव करने के लिए किया जाता है.

lib/data.dart

class Block {
  final String type;
  final String text;
  Block(this.type, this.text);

  factory Block.fromJson(Map<String, dynamic> json) {
    if (json case {'type': final type, 'text': final text}) {
      return Block(type, text);
    } else {
      throw const FormatException('Unexpected JSON format');
    }
  }
}

फ़ैक्ट्री कंस्ट्रक्टर fromJson(), मैप पैटर्न के साथ इसी तरह के केस का इस्तेमाल करता है. ऐसा आपने पहले देखा था.

ध्यान दें कि json, मैप के पैटर्न से मेल खाता है. हालांकि, पैटर्न में किसी एक कुंजी checked को शामिल नहीं किया गया है. मैप पैटर्न, मैप ऑब्जेक्ट की ऐसी किसी भी एंट्री को अनदेखा करते हैं जिन्हें पैटर्न में साफ़ तौर पर शामिल नहीं किया गया है.

ब्लॉक ऑब्जेक्ट की सूची दिखाना

  • इसके बाद, Document क्लास में getBlocks() नाम का एक नया फ़ंक्शन जोड़ें. getBlocks(), JSON को Block क्लास के इंस्टेंस में पार्स करता है और आपके यूज़र इंटरफ़ेस (यूआई) में रेंडर करने के लिए ब्लॉक की सूची दिखाता है:

lib/data.dart

class Document {
  final Map<String, Object?> _json;
  Document() : _json = jsonDecode(documentJson);

  (String, {DateTime modified}) get metadata {
    if (_json
        case {
          'metadata': {
            'title': String title,
            'modified': String localModified,
          }
        }) {
      return (title, modified: DateTime.parse(localModified));
    } else {
      throw const FormatException('Unexpected JSON');
    }
  }

  List<Block> getBlocks() {                                  // Add from here...
    if (_json case {'blocks': List blocksJson}) {
      return [for (final blockJson in blocksJson) Block.fromJson(blockJson)];
    } else {
      throw const FormatException('Unexpected JSON format');
    }
  }                                                          // to here.
}

getBlocks() फ़ंक्शन, Block ऑब्जेक्ट की सूची दिखाता है, जिसका इस्तेमाल आप बाद में यूज़र इंटरफ़ेस (यूआई) बनाने के लिए करते हैं. एक जाना-पहचाना if-case स्टेटमेंट पुष्टि करता है और blocks मेटाडेटा की वैल्यू को blocksJson नाम वाले एक नए List में कास्ट करता है (पैटर्न के बिना, आपको कास्ट करने के लिए toList() तरीके का इस्तेमाल करना होगा).

नई सूची को Block ऑब्जेक्ट से भरने के लिए, लिटरल सूची में इसका संग्रह होता है.

यह सेक्शन, पैटर्न से जुड़ी ऐसी किसी भी सुविधा के बारे में नहीं बताता है जिसे आपने इस कोडलैब में पहले से न आज़माया हो. अगले चरण में, आपको अपने यूज़र इंटरफ़ेस (यूआई) में सूची के आइटम रेंडर करने की तैयारी करनी होगी.

9. दस्तावेज़ दिखाने के लिए पैटर्न का इस्तेमाल करें

अब आपने if-case स्टेटमेंट और रीफ़्यूटेबल पैटर्न का इस्तेमाल करके, JSON डेटा को डीस्ट्रक्चर करके उसे फिर से बनाने के लिए इस्तेमाल किया है. लेकिन if-case, पैटर्न के साथ आने वाली फ़्लो स्ट्रक्चर को कंट्रोल करने के सिर्फ़ एक बेहतर तरीके है. अब, स्टेटमेंट बदलने के लिए मुश्किल पैटर्न की अपनी जानकारी का इस्तेमाल करें.

स्विच स्टेटमेंट का इस्तेमाल करके तय करें कि क्या रेंडर होना है

  • main.dart में, BlockWidget नाम का एक नया विजेट बनाएं, जो अपने type फ़ील्ड के आधार पर हर ब्लॉक की स्टाइल तय करता है.

lib/main.dart

class BlockWidget extends StatelessWidget {
  final Block block;

  const BlockWidget({
    required this.block,
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    TextStyle? textStyle;
    switch (block.type) {
      case 'h1':
        textStyle = Theme.of(context).textTheme.displayMedium;
      case 'p' || 'checkbox':
        textStyle = Theme.of(context).textTheme.bodyMedium;
      case _:
        textStyle = Theme.of(context).textTheme.bodySmall;
    }

    return Container(
      margin: const EdgeInsets.all(8),
      child: Text(
        block.text,
        style: textStyle,
      ),
    );
  }
}

build तरीके में मौजूद स्विच स्टेटमेंट, block ऑब्जेक्ट के type फ़ील्ड को चालू करता है.

  1. पहले केस स्टेटमेंट में कॉन्सटेंट स्ट्रिंग पैटर्न का इस्तेमाल किया गया है. अगर block.type, कॉन्स्टेंट वैल्यू h1 के बराबर है, तो पैटर्न मैच करता है.
  2. दूसरे केस स्टेटमेंट में ऐसे लॉजिकल-या पैटर्न का इस्तेमाल किया जाता है जिसके सबपैटर्न के तौर पर, दो कॉन्स्टेंट स्ट्रिंग पैटर्न होते हैं. अगर block.type, p या checkbox में से किसी एक सब-पैटर्न से मेल खाता है, तो पैटर्न मैच होता है.
  1. आखिरी मामला एक वाइल्डकार्ड पैटर्न, _ है. स्विच केस में वाइल्डकार्ड बाकी सभी चीज़ों से मेल खाते हैं. ये default क्लॉज़ की तरह ही काम करते हैं, जिनकी अब भी Switch स्टेटमेंट में अनुमति है (ये सिर्फ़ ज़्यादा शब्दों वाले हैं).

वाइल्डकार्ड पैटर्न का इस्तेमाल उन जगहों पर किया जा सकता है जहां पैटर्न की अनुमति हो—उदाहरण के लिए, वैरिएबल डिक्लेरेशन पैटर्न में: var (title, _) = document.metadata;

इस कॉन्टेक्स्ट में, वाइल्डकार्ड किसी भी वैरिएबल को बाइंड नहीं करता है. यह दूसरे फ़ील्ड को खारिज कर देता है.

अगले सेक्शन में, Block ऑब्जेक्ट दिखाने के बाद, स्विच करने की सुविधाओं के बारे में बताया गया है.

दस्तावेज़ का कॉन्टेंट दिखाएं

DocumentScreen विजेट के build तरीके में getBlocks() को कॉल करके, ऐसा लोकल वैरिएबल बनाएं जिसमें Block ऑब्जेक्ट की सूची शामिल हो.

  1. DocumentationScreen में build के मौजूदा तरीके को इस वर्शन से बदलें:

lib/main.dart

class DocumentScreen extends StatelessWidget {
  final Document document;

  const DocumentScreen({
    required this.document,
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    final (title, :modified) = document.metadata;
    final blocks = document.getBlocks();                           // Add this line

    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Column(
        children: [
          Text('Last modified: $modified'),                        // Modify from here
          Expanded(
            child: ListView.builder(
              itemCount: blocks.length,
              itemBuilder: (context, index) {
                return BlockWidget(block: blocks[index]);
              },
            ),
          ),                                                       // to here.
        ],
      ),
    );
  }
}

लाइन BlockWidget(block: blocks[index]), getBlocks() तरीके से लौटाए गए ब्लॉक की सूची में मौजूद हर आइटम के लिए, एक BlockWidget विजेट बनाती है.

  1. ऐप्लिकेशन चलाएं और फिर आपको स्क्रीन पर ब्लॉक दिखने लगेंगे:

&#39;ब्लॉक&#39; में मौजूद कॉन्टेंट दिखाने वाले ऐप्लिकेशन का स्क्रीनशॉट सेक्शन में मिलेगा.

10. स्विच एक्सप्रेशन का इस्तेमाल करना

पैटर्न की मदद से, switch और case में कई नई सुविधाएं जोड़ी जा सकती हैं. उन्हें ज़्यादा जगहों पर इस्तेमाल करने के लिए, Dart ने एक्सप्रेशन स्विच किए हैं. केस की सीरीज़ से, वैरिएबल असाइनमेंट या रिटर्न स्टेटमेंट के लिए सीधे तौर पर वैल्यू दी जा सकती है.

स्विच स्टेटमेंट को स्विच एक्सप्रेशन में बदलें

डार्ट एनालाइज़र, आपके कोड में बदलाव करने में आपकी मदद करने के लिए सहायता टीम उपलब्ध कराता है.

  1. अपने कर्सर को पिछले सेक्शन से स्विच स्टेटमेंट पर ले जाएं.
  2. उपलब्ध असिस्ट देखने के लिए लाइट बल्ब पर क्लिक करें.
  3. स्विच एक्सप्रेशन में बदलें असिस्ट चुनें.

&#39;स्विच एक्सप्रेशन में बदलें&#39; बटन का स्क्रीनशॉट VS Code में सहायता उपलब्ध है.

इस कोड का नया वर्शन कुछ ऐसा दिखता है:

lib/main.dart

class BlockWidget extends StatelessWidget {
  final Block block;

  const BlockWidget({
    required this.block,
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    TextStyle? textStyle;                                          // Modify from here
    textStyle = switch (block.type) {
      'h1' => Theme.of(context).textTheme.displayMedium,
      'p' || 'checkbox' => Theme.of(context).textTheme.bodyMedium,
      _ => Theme.of(context).textTheme.bodySmall
    };                                                             // to here.

    return Container(
      margin: const EdgeInsets.all(8),
      child: Text(
        block.text,
        style: textStyle,
      ),
    );
  }
}

स्विच एक्सप्रेशन, किसी स्विच स्टेटमेंट की तरह ही दिखता है, लेकिन यह case कीवर्ड को हटा देता है और पैटर्न को केस के मुख्य भाग से अलग करने के लिए => का इस्तेमाल करता है. स्विच स्टेटमेंट से उलट, स्विच एक्सप्रेशन से वैल्यू मिलती है. साथ ही, जहां भी एक्सप्रेशन का इस्तेमाल किया जा सकता है वहां इसका इस्तेमाल किया जा सकता है.

11. ऑब्जेक्ट पैटर्न का इस्तेमाल करें

Dart एक भाषा है, जो सिर्फ़ ऑब्जेक्ट पर आधारित है, इसलिए पैटर्न सभी ऑब्जेक्ट पर लागू होते हैं. इस चरण में, ऑब्जेक्ट पैटर्न को चालू किया जाता है और अपने यूज़र इंटरफ़ेस (यूआई) के तारीख रेंडरिंग लॉजिक को बेहतर बनाने के लिए, ऑब्जेक्ट प्रॉपर्टी को डीस्ट्रक्चर किया जाता है.

ऑब्जेक्ट पैटर्न से प्रॉपर्टी एक्सट्रैक्ट करना

इस सेक्शन में, पैटर्न का इस्तेमाल करके बेहतर तरीके से बदलाव किया जाता है कि पिछली बार बदलाव की तारीख कैसे दिखाई गई हो.

  • main.dart में formatDate तरीका जोड़ें:

lib/main.dart

String formatDate(DateTime dateTime) {
  final today = DateTime.now();
  final difference = dateTime.difference(today);

  return switch (difference) {
    Duration(inDays: 0) => 'today',
    Duration(inDays: 1) => 'tomorrow',
    Duration(inDays: -1) => 'yesterday',
    Duration(inDays: final days, isNegative: true) => '${days.abs()} days ago',
    Duration(inDays: final days) => '$days days from now',
  };
}

इस तरीके से, स्विच एक्सप्रेशन की सुविधा मिलती है. यह वैल्यू difference, Duration ऑब्जेक्ट पर स्विच करती है. यह JSON डेटा के today और modified वैल्यू के बीच के समय के बारे में बताता है.

स्विच एक्सप्रेशन का हर केस, ऐसे ऑब्जेक्ट पैटर्न का इस्तेमाल कर रहा है जो ऑब्जेक्ट की प्रॉपर्टी inDays और isNegative पर गैटर को कॉल करके मैच करता है. सिंटैक्स ऐसा लग रहा है कि वह Duration ऑब्जेक्ट को बना रहा है, लेकिन असल में यह difference ऑब्जेक्ट के फ़ील्ड को ऐक्सेस कर रहा है.

पहले तीन केस, ऑब्जेक्ट प्रॉपर्टी inDays से मैच करने और उससे जुड़ी स्ट्रिंग देने के लिए, कॉन्सटैंट सब-पैटर्न 0, 1, और -1 का इस्तेमाल करते हैं.

आखिरी दो मामलों में आज, बीते हुए कल, और आने वाले कल के बाद की अवधियां हैंडल की गई हैं:

  • अगर isNegative प्रॉपर्टी, बूलियन कॉन्सटेंट पैटर्न true से मेल खाती है, तो इसका मतलब है कि बदलाव की तारीख पहले की थी, तो दिन पहले दिखती है.
  • अगर इस मामले में अंतर नहीं आता है, तो अवधि पॉज़िटिव दिनों की होनी चाहिए (isNegative: false की मदद से इसकी पुष्टि करने की ज़रूरत नहीं है). इसलिए, बदलाव की तारीख आगे की है और आज से बाद के दिन दिखेगी.

हफ़्तों के लिए फ़ॉर्मैटिंग का लॉजिक जोड़ें

  • सात दिनों से ज़्यादा की अवधि की पहचान करने के लिए, अपने फ़ॉर्मैटिंग फ़ंक्शन में दो नए केस जोड़ें, ताकि यूज़र इंटरफ़ेस (यूआई) उन्हें हफ़्ते के तौर पर दिखा सके:

lib/main.dart

String formatDate(DateTime dateTime) {
  final today = DateTime.now();
  final difference = dateTime.difference(today);

  return switch (difference) {
    Duration(inDays: 0) => 'today',
    Duration(inDays: 1) => 'tomorrow',
    Duration(inDays: -1) => 'yesterday',
    Duration(inDays: final days) when days > 7 => '${days ~/ 7} weeks from now', // Add from here
    Duration(inDays: final days) when days < -7 =>
      '${days.abs() ~/ 7} weeks ago',                                            // to here.
    Duration(inDays: final days, isNegative: true) => '${days.abs()} days ago',
    Duration(inDays: final days) => '$days days from now',
  };
}

इस कोड में गार्ड क्लॉज़ के बारे में जानकारी दी गई है:

  • गार्ड क्लॉज़, केस पैटर्न के बाद when कीवर्ड का इस्तेमाल करता है.
  • इनका इस्तेमाल अगर-केस, स्विच स्टेटमेंट, और स्विच एक्सप्रेशन में किया जा सकता है.
  • वे सिर्फ़ मैच होने के बाद पैटर्न में कोई शर्त जोड़ते हैं.
  • अगर गार्ड क्लॉज़ का आकलन गलत होता है, तो पूरे पैटर्न को अस्वीकार किया जाता है और अगले केस पर लागू किया जाता है.

यूज़र इंटरफ़ेस (यूआई) में फ़ॉर्मैट की गई नई तारीख जोड़ना

  1. आखिर में, formatDate फ़ंक्शन का इस्तेमाल करने के लिए, DocumentScreen में build तरीके को अपडेट करें:

lib/main.dart

class DocumentScreen extends StatelessWidget {
  final Document document;

  const DocumentScreen({
    required this.document,
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    final (title, :modified) = document.metadata;
    final formattedModifiedDate = formatDate(modified);            // Add this line
    final blocks = document.getBlocks();

    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Column(
        children: [
          Text('Last modified: $formattedModifiedDate'),           // Modify this line
          Expanded(
            child: ListView.builder(
              itemCount: blocks.length,
              itemBuilder: (context, index) {
                return BlockWidget(block: blocks[index]);
              },
            ),
          ),
        ],
      ),
    );
  }
}
  1. अपने ऐप्लिकेशन में हुए बदलाव देखने के लिए, फिर से लोड करें:

ऐप्लिकेशन का स्क्रीनशॉट, जिसमें &#39;पिछली बार किए गए बदलाव की तारीख: दो हफ़्ते पहले&#39; स्ट्रिंग दिख रही है को फ़ॉर्मैट करने की ज़रूरत नहीं होती.

12. पूरी तरह से स्विच करने के लिए क्लास को सील करें

ध्यान दें कि आपने आखिरी स्विच के आखिर में, किसी वाइल्डकार्ड या डिफ़ॉल्ट केस का इस्तेमाल नहीं किया है. हालांकि, उन वैल्यू के लिए हमेशा एक केस शामिल करना अच्छा तरीका है जिनकी वजह से कोई वैल्यू छूट सकती है, लेकिन इस तरह के आसान उदाहरण में ऐसा किया जा सकता है. ऐसा इसलिए, क्योंकि आपको उन मामलों के बारे में पता है जो सभी संभावित वैल्यू inDays के लिए तय किए गए हैं.

जब किसी स्विच में मौजूद हर केस को हैंडल किया जाता है, तो उसे पूरी जानकारी देने वाला स्विच कहा जाता है. उदाहरण के लिए, अगर true और false के केस हैं, तो bool टाइप पर स्विच करने के दौरान, कई काम नहीं किए जा सकते. ईनम के हर मान के लिए केस होने पर enum प्रकार पर स्विच करना काफ़ी नहीं होगा, क्योंकि एनम निरंतर मानों की तय संख्या को दिखाते हैं.

डार्ट 3 में, नए क्लास मॉडिफ़ायर sealed का इस्तेमाल करके, ऑब्जेक्ट और क्लास की हैरारकी के लिए, पूरी जानकारी की जांच की सुविधा को बढ़ाया गया है. सील की गई सुपर क्लास के तौर पर, अपनी Block क्लास को रीफ़ैक्ट करें.

सब-क्लास बनाना

  • data.dart में, तीन नई क्लास बनाएं—HeaderBlock, ParagraphBlock, और CheckboxBlock—जो Block का विस्तार करती हों:

lib/data.dart

class HeaderBlock extends Block {
  final String text;
  HeaderBlock(this.text);
}

class ParagraphBlock extends Block {
  final String text;
  ParagraphBlock(this.text);
}

class CheckboxBlock extends Block {
  final String text;
  final bool isChecked;
  CheckboxBlock(this.text, this.isChecked);
}

इनमें से हर क्लास, ओरिजनल JSON के अलग-अलग type वैल्यू से मेल खाती है: 'h1', 'p', और 'checkbox'.

सुपरक्लास का भरपूर आनंद लें

  • Block क्लास को sealed के तौर पर मार्क करें. इसके बाद, if-case को स्विच एक्सप्रेशन के तौर पर रीफ़ैक्टर करें, जो JSON में बताए गए type से जुड़ी सब-क्लास दिखाता है:

lib/data.dart

sealed class Block {
  Block();

  factory Block.fromJson(Map<String, Object?> json) {
    return switch (json) {
      {'type': 'h1', 'text': String text} => HeaderBlock(text),
      {'type': 'p', 'text': String text} => ParagraphBlock(text),
      {'type': 'checkbox', 'text': String text, 'checked': bool checked} =>
        CheckboxBlock(text, checked),
      _ => throw const FormatException('Unexpected JSON format'),
    };
  }
}

sealed कीवर्ड एक क्लास मॉडिफ़ायर है. इसका मतलब है कि इस क्लास को सिर्फ़ उसी लाइब्रेरी में बढ़ाया या लागू किया जा सकता है. ऐनालाइज़र को इस क्लास के सब-टाइप के बारे में जानकारी होती है. इसलिए, अगर स्विच इनमें से किसी एक को कवर नहीं कर पाता है, तो यह गड़बड़ी की सूचना देता है. हालांकि, इसमें और भी कई बातें शामिल हो सकती हैं.

विजेट दिखाने के लिए, स्विच एक्सप्रेशन का इस्तेमाल करें

  1. main.dart की BlockWidget क्लास को ऐसे स्विच एक्सप्रेशन से अपडेट करें जो हर केस के लिए ऑब्जेक्ट पैटर्न का इस्तेमाल करता हो:

lib/main.dart

class BlockWidget extends StatelessWidget {
  final Block block;

  const BlockWidget({
    required this.block,
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.all(8),
      child: switch (block) {
        HeaderBlock(:final text) => Text(
            text,
            style: Theme.of(context).textTheme.displayMedium,
          ),
        ParagraphBlock(:final text) => Text(text),
        CheckboxBlock(:final text, :final isChecked) => Row(
            children: [
              Checkbox(value: isChecked, onChanged: (_) {}),
              Text(text),
            ],
          ),
      },
    );
  }
}

BlockWidget के पहले वर्शन में, आपने TextStyle देने के लिए Block ऑब्जेक्ट के फ़ील्ड को चालू किया. अब Block ऑब्जेक्ट के इंस्टेंस को बदला जा सकता है और उसका मिलान ऑब्जेक्ट पैटर्न से किया जाता है. यह पैटर्न, इसकी सब-क्लास को दिखाता है और इस प्रोसेस में ऑब्जेक्ट की प्रॉपर्टी निकालता है.

डार्ट एनालाइज़र, यह जांच कर सकता है कि स्विच एक्सप्रेशन में हर सब-क्लास को हैंडल किया जाता है, क्योंकि आपने Block को सील की गई क्लास बनाया है.

यह भी ध्यान रखें कि यहां स्विच एक्सप्रेशन का इस्तेमाल करके, नतीजे को सीधे child एलिमेंट में पास किया जा सकता है. इससे पहले ज़रूरी रिटर्न स्टेटमेंट नहीं दिखेगा.

  1. पहली बार रेंडर किया गया JSON डेटा देखने के लिए, वेब पर फिर से लोड करें:

ऐप्लिकेशन का स्क्रीनशॉट, जिसमें &#39;Dart 3 सीखें&#39; चेकबॉक्स दिख रहा है

13. बधाई हो

आपने पैटर्न, रिकॉर्ड, बेहतर स्विच और केस, और सील की गई क्लास के साथ प्रयोग करने में कामयाबी हासिल की है. आपने बहुत सारी जानकारी दी, लेकिन इन सुविधाओं के बारे में अभी तक बहुत कुछ नहीं बताया गया है. पैटर्न के बारे में ज़्यादा जानकारी के लिए, सुविधा की खास बातें देखें.

अलग-अलग तरह के पैटर्न, अलग-अलग कॉन्टेक्स्ट, जिनमें वे दिख सकते हैं, और सबपैटर्न की संभावित नेस्ट होने की वजह से, व्यवहार की संभावनाएं खत्म हो जाती हैं. हालांकि, इन्हें आसानी से देखा जा सकता है.

पैटर्न का इस्तेमाल करके, Flutter में कॉन्टेंट दिखाने के सभी तरीकों की कल्पना की जा सकती है. पैटर्न का इस्तेमाल करके, सुरक्षित तरीके से डेटा एक्सट्रैक्ट करके कोड की कुछ लाइनों में अपना यूज़र इंटरफ़ेस (यूआई) बनाया जा सकता है.

आगे क्या होगा?

  • Dart के दस्तावेज़ के भाषा सेक्शन में, पैटर्न, रिकॉर्ड, बेहतर स्विच और केस, और क्लास मॉडिफ़ायर से जुड़े दस्तावेज़ देखें.

पहचान फ़ाइलें

flutter/codelabs डेटा स्टोर करने की जगह में, सिलसिलेवार तरीके से पूरा सैंपल कोड देखें.

हर नई सुविधा के बारे में गहराई से जानने के लिए, डिज़ाइन से जुड़े ओरिजनल दस्तावेज़ देखें: