1. परिचय
Dart 3 भाषा के लिए पैटर्न पेश करता है, जो व्याकरण की एक नई श्रेणी है. Dart कोड लिखने के इस नए तरीके के अलावा, अन्य कई भाषाएँ बेहतर हैं जिनमें ये शामिल हैं
- अलग-अलग तरह के डेटा का बंडल बनाने के लिए रिकॉर्ड,
- क्लास मॉडिफ़ायर का इस्तेमाल करके ऐक्सेस कंट्रोल कर सकते हैं और
- नए स्विच एक्सप्रेशन और if-case स्टेटमेंट होंगे.
इन सुविधाओं से, Dart कोड लिखने के दौरान मिलने वाले विकल्पों में ज़्यादा विकल्प मिलते हैं. इस कोडलैब में, आपको अपने कोड को ज़्यादा कॉम्पैक्ट, व्यवस्थित, और सुविधाजनक बनाने के लिए, उनके इस्तेमाल का तरीका पता चलेगा.
यह कोडलैब यह मानकर चलता है कि आपको Flutter और Dart के बारे में जानकारी है. अगर आपको थोड़ी जंग लग रही है, तो इन संसाधनों की मदद से बुनियादी चीज़ों को ठीक करने के बारे में सोचें:
आपको क्या बनाना होगा
यह कोडलैब एक ऐसा ऐप्लिकेशन बनाता है जो Flutter में JSON दस्तावेज़ दिखाता है. यह ऐप्लिकेशन, किसी बाहरी सोर्स से आने वाले JSON को सिम्युलेट करता है. JSON में, दस्तावेज़ का डेटा मौजूद होता है. जैसे, बदलाव की तारीख, टाइटल, हेडर, और पैराग्राफ़. रिकॉर्ड में सही तरीके से डेटा पैक करने के लिए कोड लिखे जाते हैं, ताकि आपके Flutter विजेट की ज़रूरत पड़ने पर उन्हें ट्रांसफ़र और अनपैक किया जा सके.
इसके बाद, वैल्यू के उस पैटर्न से मेल खाने पर, सही विजेट बनाने के लिए पैटर्न का इस्तेमाल किया जाता है. साथ ही, यह भी देखा जा सकता है कि लोकल वैरिएबल में डेटा को व्यवस्थित करने के लिए, पैटर्न का इस्तेमाल कैसे किया जाता है.
आपको इनके बारे में जानकारी मिलेगी
- ऐसा रिकॉर्ड कैसे बनाएं जिसमें अलग-अलग टाइप के लिए एक से ज़्यादा वैल्यू सेव की गई हों.
- रिकॉर्ड का इस्तेमाल करके, किसी फ़ंक्शन से एक से ज़्यादा वैल्यू पाने का तरीका.
- रिकॉर्ड और अन्य ऑब्जेक्ट से डेटा का मिलान करने, उसकी पुष्टि करने, और उसे अलग करने के लिए, पैटर्न का इस्तेमाल कैसे करें.
- पैटर्न से मेल खाने वाली वैल्यू को नए या मौजूदा वैरिएबल से बाइंड करने का तरीका.
- नई स्विच स्टेटमेंट क्षमताओं, स्विच एक्सप्रेशन, और 'अगर-केस स्टेटमेंट' का इस्तेमाल करने का तरीका जानें.
- यह पक्का करने के लिए कि हर मामले को स्विच स्टेटमेंट या स्विच एक्सप्रेशन में हैंडल किया जाता हो, पूरी जानकारी की जांच करने की सुविधा का फ़ायदा लें.
2. अपना एनवायरमेंट सेट अप करें
- Flutter SDK टूल इंस्टॉल करें.
- विज़ुअल स्टूडियो कोड (वीएस कोड) जैसा एडिटर सेट अप करें.
- कम से कम एक टारगेट प्लैटफ़ॉर्म (iOS, Android, डेस्कटॉप या वेब ब्राउज़र) के लिए, प्लैटफ़ॉर्म सेटअप करने का तरीका देखें.
3. प्रोजेक्ट बनाएं
पैटर्न, रिकॉर्ड, और अन्य नई सुविधाओं के बारे में जानने से पहले, कुछ समय निकालकर एक ऐसा आसान Flutter प्रोजेक्ट बनाएं जिसके लिए आपको अपना पूरा कोड लिखना होगा.
Flutter प्रोजेक्ट बनाना
patterns_codelab
नाम का नया प्रोजेक्ट बनाने के लिए,flutter create
कमांड का इस्तेमाल करें.--empty
फ़्लैगlib/main.dart
फ़ाइल में स्टैंडर्ड काउंटर ऐप्लिकेशन बनाने से रोकता है जिसे आपको फिर भी हटाना होगा.
flutter create --empty patterns_codelab
- इसके बाद, वीएस कोड का इस्तेमाल करके
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
फ़ाइल बनाता है.
- ऐप्लिकेशन के लिए शुरुआती पॉइंट बनाने के लिए,
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
विजेट का इस्तेमाल करके, पेज का विज़ुअल लेआउट उपलब्ध कराता है.
- यह पक्का करने के लिए कि सब कुछ ठीक से चल रहा है, चलाएं और डीबग करें पर क्लिक करके अपनी होस्ट मशीन पर ऐप्लिकेशन चलाएं:
- डिफ़ॉल्ट रूप से, 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
होता है.
रिकॉर्ड फ़ील्ड ऐक्सेस करना
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
- ऐप्लिकेशन में दिख रही JSON वैल्यू देखने के लिए, पेज को फिर से लोड करें. जब भी आप कोई फ़ाइल सेव करते हैं, तो वीएस कोड डार्ट प्लगिन हॉट-रीलोड हो जाता है.
आप देख सकते हैं कि हर फ़ील्ड ने असल में अपना टाइप बनाए रखा है.
Text()
तरीका, स्ट्रिंग को पहले तर्क के तौर पर लेता है.modified
फ़ील्ड, DateTime है. इसे स्ट्रिंग इंटरपोलेशन का इस्तेमाल करके,String
में बदला जाता है.
अलग-अलग तरह का डेटा वापस करने का दूसरा सुरक्षित तरीका है क्लास तय करना, जो ज़्यादा शब्दों में जानकारी देती है.
6. पैटर्न की मदद से मिलान करना और व्यवस्थित करना
रिकॉर्ड, अलग-अलग तरह के डेटा को बेहतर तरीके से इकट्ठा कर सकते हैं और उन्हें आसानी से पास कर सकते हैं. अब, पैटर्न का इस्तेमाल करके अपने कोड को बेहतर बनाएं.
पैटर्न ऐसा स्ट्रक्चर दिखाता है जिसमें एक या उससे ज़्यादा वैल्यू हो सकती हैं, जैसे कि ब्लूप्रिंट. पैटर्न की तुलना असल वैल्यू से की जाती है, ताकि यह पता लगाया जा सके कि वे मिलते-जुलते हैं या नहीं.
कुछ पैटर्न मैच होने पर, मैच होने वाली वैल्यू को डिस्ट्रक्चर करने के लिए, डेटा को उससे अलग कर देते हैं. डिस्ट्रक्चर करने की सुविधा से, किसी ऑब्जेक्ट की वैल्यू को अनपैक किया जा सकता है. ऐसा करके, उन्हें लोकल वैरिएबल के लिए असाइन किया जा सकता है या उन वैल्यू को मैच किया जा सकता है.
किसी रिकॉर्ड को लोकल वैरिएबल के हिसाब से बनाना
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
लिखें.
- पिछले चरण जैसा नतीजा देखने के लिए, फिर से लोड करें. काम करने के तरीके में कोई बदलाव नहीं होता है; आपने अपने कोड को और छोटा बनाया है.
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
फ़ील्ड को चालू करता है.
- पहले केस स्टेटमेंट में कॉन्सटेंट स्ट्रिंग पैटर्न का इस्तेमाल किया गया है. अगर
block.type
, कॉन्स्टेंट वैल्यूh1
के बराबर है, तो पैटर्न मैच करता है. - दूसरे केस स्टेटमेंट में ऐसे लॉजिकल-या पैटर्न का इस्तेमाल किया जाता है जिसके सबपैटर्न के तौर पर, दो कॉन्स्टेंट स्ट्रिंग पैटर्न होते हैं. अगर
block.type
,p
याcheckbox
में से किसी एक सब-पैटर्न से मेल खाता है, तो पैटर्न मैच होता है.
- आखिरी मामला एक वाइल्डकार्ड पैटर्न,
_
है. स्विच केस में वाइल्डकार्ड बाकी सभी चीज़ों से मेल खाते हैं. येdefault
क्लॉज़ की तरह ही काम करते हैं, जिनकी अब भी Switch स्टेटमेंट में अनुमति है (ये सिर्फ़ ज़्यादा शब्दों वाले हैं).
वाइल्डकार्ड पैटर्न का इस्तेमाल उन जगहों पर किया जा सकता है जहां पैटर्न की अनुमति हो—उदाहरण के लिए, वैरिएबल डिक्लेरेशन पैटर्न में: var (title, _) = document.metadata;
इस कॉन्टेक्स्ट में, वाइल्डकार्ड किसी भी वैरिएबल को बाइंड नहीं करता है. यह दूसरे फ़ील्ड को खारिज कर देता है.
अगले सेक्शन में, Block
ऑब्जेक्ट दिखाने के बाद, स्विच करने की सुविधाओं के बारे में बताया गया है.
दस्तावेज़ का कॉन्टेंट दिखाएं
DocumentScreen
विजेट के build
तरीके में getBlocks()
को कॉल करके, ऐसा लोकल वैरिएबल बनाएं जिसमें Block
ऑब्जेक्ट की सूची शामिल हो.
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
विजेट बनाती है.
- ऐप्लिकेशन चलाएं और फिर आपको स्क्रीन पर ब्लॉक दिखने लगेंगे:
10. स्विच एक्सप्रेशन का इस्तेमाल करना
पैटर्न की मदद से, switch
और case
में कई नई सुविधाएं जोड़ी जा सकती हैं. उन्हें ज़्यादा जगहों पर इस्तेमाल करने के लिए, Dart ने एक्सप्रेशन स्विच किए हैं. केस की सीरीज़ से, वैरिएबल असाइनमेंट या रिटर्न स्टेटमेंट के लिए सीधे तौर पर वैल्यू दी जा सकती है.
स्विच स्टेटमेंट को स्विच एक्सप्रेशन में बदलें
डार्ट एनालाइज़र, आपके कोड में बदलाव करने में आपकी मदद करने के लिए सहायता टीम उपलब्ध कराता है.
- अपने कर्सर को पिछले सेक्शन से स्विच स्टेटमेंट पर ले जाएं.
- उपलब्ध असिस्ट देखने के लिए लाइट बल्ब पर क्लिक करें.
- स्विच एक्सप्रेशन में बदलें असिस्ट चुनें.
इस कोड का नया वर्शन कुछ ऐसा दिखता है:
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
कीवर्ड का इस्तेमाल करता है. - इनका इस्तेमाल अगर-केस, स्विच स्टेटमेंट, और स्विच एक्सप्रेशन में किया जा सकता है.
- वे सिर्फ़ मैच होने के बाद पैटर्न में कोई शर्त जोड़ते हैं.
- अगर गार्ड क्लॉज़ का आकलन गलत होता है, तो पूरे पैटर्न को अस्वीकार किया जाता है और अगले केस पर लागू किया जाता है.
यूज़र इंटरफ़ेस (यूआई) में फ़ॉर्मैट की गई नई तारीख जोड़ना
- आखिर में,
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]);
},
),
),
],
),
);
}
}
- अपने ऐप्लिकेशन में हुए बदलाव देखने के लिए, फिर से लोड करें:
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
कीवर्ड एक क्लास मॉडिफ़ायर है. इसका मतलब है कि इस क्लास को सिर्फ़ उसी लाइब्रेरी में बढ़ाया या लागू किया जा सकता है. ऐनालाइज़र को इस क्लास के सब-टाइप के बारे में जानकारी होती है. इसलिए, अगर स्विच इनमें से किसी एक को कवर नहीं कर पाता है, तो यह गड़बड़ी की सूचना देता है. हालांकि, इसमें और भी कई बातें शामिल हो सकती हैं.
विजेट दिखाने के लिए, स्विच एक्सप्रेशन का इस्तेमाल करें
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
एलिमेंट में पास किया जा सकता है. इससे पहले ज़रूरी रिटर्न स्टेटमेंट नहीं दिखेगा.
- पहली बार रेंडर किया गया JSON डेटा देखने के लिए, वेब पर फिर से लोड करें:
13. बधाई हो
आपने पैटर्न, रिकॉर्ड, बेहतर स्विच और केस, और सील की गई क्लास के साथ प्रयोग करने में कामयाबी हासिल की है. आपने बहुत सारी जानकारी दी, लेकिन इन सुविधाओं के बारे में अभी तक बहुत कुछ नहीं बताया गया है. पैटर्न के बारे में ज़्यादा जानकारी के लिए, सुविधा की खास बातें देखें.
अलग-अलग तरह के पैटर्न, अलग-अलग कॉन्टेक्स्ट, जिनमें वे दिख सकते हैं, और सबपैटर्न की संभावित नेस्ट होने की वजह से, व्यवहार की संभावनाएं खत्म हो जाती हैं. हालांकि, इन्हें आसानी से देखा जा सकता है.
पैटर्न का इस्तेमाल करके, Flutter में कॉन्टेंट दिखाने के सभी तरीकों की कल्पना की जा सकती है. पैटर्न का इस्तेमाल करके, सुरक्षित तरीके से डेटा एक्सट्रैक्ट करके कोड की कुछ लाइनों में अपना यूज़र इंटरफ़ेस (यूआई) बनाया जा सकता है.
आगे क्या होगा?
- Dart के दस्तावेज़ के भाषा सेक्शन में, पैटर्न, रिकॉर्ड, बेहतर स्विच और केस, और क्लास मॉडिफ़ायर से जुड़े दस्तावेज़ देखें.
पहचान फ़ाइलें
flutter/codelabs
डेटा स्टोर करने की जगह में, सिलसिलेवार तरीके से पूरा सैंपल कोड देखें.
हर नई सुविधा के बारे में गहराई से जानने के लिए, डिज़ाइन से जुड़े ओरिजनल दस्तावेज़ देखें: