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

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

इस कोडलैब (कोड बनाना सीखने के लिए ट्यूटोरियल) के बारे में जानकारी

subjectपिछली बार अप्रैल 4, 2025 को अपडेट किया गया
account_circleJohn Ryan and Marya Belanger ने लिखा

1. परिचय

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

  • अलग-अलग तरह के डेटा को बंडल करने के लिए रिकॉर्ड,
  • ऐक्सेस कंट्रोल करने के लिए क्लास में बदलाव करने वाले टूल, और
  • नए switch एक्सप्रेशन और if-case स्टेटमेंट.

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

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

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

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

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

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

आपको क्या सीखने को मिलेगा

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

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

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

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

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

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

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

VS Code का स्क्रीनशॉट, जिसमें 'flutter create' कमांड से बनाया गया प्रोजेक्ट दिख रहा है.

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, यूज़र इंटरफ़ेस (यूआई) को थीम देने के लिए, Material Design का नया वर्शन सेट अप करता है.
  • DocumentScreen, Scaffold विजेट का इस्तेमाल करके पेज का विज़ुअल लेआउट दिखाता है.
  1. यह पक्का करने के लिए कि सब कुछ ठीक से काम कर रहा है, चालू करें और डीबग करें पर क्लिक करके, ऐप्लिकेशन को अपनी होस्ट मशीन पर चलाएं:

&#39;चालू करें और डीबग करें&#39; बटन की इमेज. यह बटन, बाईं ओर मौजूद गतिविधि बार के &#39;चालू करें और डीबग करें&#39; सेक्शन में उपलब्ध होता है.

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

VS Code में, टारगेट प्लैटफ़ॉर्म सिलेक्टर का स्क्रीनशॉट.

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

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

5. रिकॉर्ड बनाना और दिखाना

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

रिकॉर्ड बनाना और उसे दिखाना

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

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 होता है.

return स्टेटमेंट, दो वैल्यू को ब्रैकेट, (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 वैल्यू देखने के लिए, फ़ाइल को हॉट रीलोड करें. हर बार फ़ाइल सेव करने पर, VS Code Dart प्लग इन, फ़ाइल को हॉट रीलोड करता है.

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

इससे पता चलता है कि हर फ़ील्ड का टाइप पहले जैसा ही है.

  • Text() तरीका, अपने पहले आर्ग्युमेंट के तौर पर स्ट्रिंग लेता है.
  • modified फ़ील्ड, टाइमस्टैंप है. इसे स्ट्रिंग इंटरपोलेशन का इस्तेमाल करके, 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-statement दिख रहा है. इसे Dart 3 में पेश किया गया है. इसे if-case कहा जाता है. केस बॉडी सिर्फ़ तब लागू होती है, जब केस पैटर्न _json में मौजूद डेटा से मेल खाता हो. यह मैच, इनकमिंग JSON की पुष्टि करने के लिए, metadata के पहले वर्शन में लिखी गई वही जांच करता है. यह कोड इन चीज़ों की पुष्टि करता है:

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

अगर वैल्यू मेल नहीं खाती है, तो पैटर्न अस्वीकार कर देता है (कार्रवाई जारी रखने से इनकार करता है) और 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(), मैप पैटर्न के साथ उसी if-case का इस्तेमाल करता है जिसे आपने पहले देखा था.

आपको दिखेगा कि 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 ऑब्जेक्ट से भरने के लिए, सूची के लिटरल में collection for शामिल होता है.

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

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

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

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

  • 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 क्लॉज़ की तरह ही काम करते हैं. इन्हें अब भी स्विच स्टेटमेंट में इस्तेमाल किया जा सकता है. हालांकि, ये थोड़े ज़्यादा शब्दों वाले होते हैं.

वाइल्डकार्ड पैटर्न का इस्तेमाल, पैटर्न की अनुमति वाले किसी भी हिस्से में किया जा सकता है. उदाहरण के लिए, वैरिएबल के एलान वाले पैटर्न में: 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. ऐप्लिकेशन चलाएं. इसके बाद, आपको स्क्रीन पर ब्लॉक दिखेंगे:

JSON डेटा के &#39;ब्लॉक&#39; सेक्शन से कॉन्टेंट दिखाने वाले ऐप्लिकेशन का स्क्रीनशॉट.

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

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

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

Dart analyzer, कोड में बदलाव करने में आपकी मदद करने के लिए सहायता करता है.

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

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

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

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',
  };
}

यह तरीका एक स्विच एक्सप्रेशन दिखाता है, जो Duration ऑब्जेक्ट की वैल्यू difference को चालू करता है. यह 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 कीवर्ड का इस्तेमाल करता है.
  • इनका इस्तेमाल, if-cases, switch स्टेटमेंट, और switch एक्सप्रेशन में किया जा सकता है.
  • ये किसी पैटर्न में शर्त सिर्फ़ मैच होने के बाद जोड़ते हैं.
  • अगर गार्ड क्लॉज़ की वैल्यू गलत होती है, तो पूरे पैटर्न को अस्वीकार कर दिया जाता है और अगले केस पर कार्रवाई की जाती है.

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

  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. अपने ऐप्लिकेशन में किए गए बदलावों को देखने के लिए, हॉट रीलोड करें:

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

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

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

जब किसी स्विच में हर मामले को हैंडल किया जाता है, तो उसे पूरी जानकारी देने वाला स्विच कहा जाता है. उदाहरण के लिए, bool टाइप को चालू करना तब मुश्किल होता है, जब उसमें true और false के लिए केस हों. enum टाइप को चालू करना तब मुश्किल होता है, जब एनम की हर वैल्यू के लिए केस भी हों. इसकी वजह यह है कि एनम, कॉन्स्टेंट वैल्यू की तय संख्या दिखाते हैं.

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

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

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

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 ऑब्जेक्ट के इंस्टेंस को स्विच करें और उसकी सबक्लास दिखाने वाले ऑब्जेक्ट पैटर्न से मैच करें. इस प्रोसेस में, ऑब्जेक्ट की प्रॉपर्टी निकाली जाती हैं.

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

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

  1. चेकबॉक्स का JSON डेटा पहली बार रेंडर होने के बाद देखने के लिए, हॉट रीलोड करें:

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

13. बधाई हो

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

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

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

आगे क्या करना है?

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

रेफ़रंस दस्तावेज़

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

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