مفاهیم مقدماتی زبان برنامه نویسی دارت (Dart) – بخش اول
دارت از سوی گوگل ایجاد شده است و هدف اولیه آن مقابله با زبانهای مبتنی بر C مانند ++C# ،C و جاوا بوده است. دارت یک زبان برنامهنویسی چندمنظوره است که زمان کامپایل سریعی دارد، منسجم است و همچنین یادگیری آن آسان است. دارت کاملاً شیءگرا، با نوعبندی اختیاری و یک زبان مبتنی بر کلاس است که پشتیبانی مناسبی از برنامهنویسی «تابعی» (Functional) و همچنین «واکنشی» (Reactive) دارد. اگر این اصطلاحها برای شما ناآشنا هستند، جای نگرانی نیست، چون ما در این مقاله از مبانی اولیه برنامهنویسی آغاز میکنیم و همه این مفاهیم را در طی این نوشته آموزش خواهیم داد. در ادامه به معرفی مفاهیم عمده برنامهنویسی میپردازیم.
مبانی برنامهنویسی
یک برنامه رایانهای به مجموعهای از دستورالعملها، یعنی یک توالی از دستورهای کوچک مستقل گفته میشود که یکی پس از دیگری میآیند.
این دستورالعملها ممکن است 5 خط یا 1000 خط باشند و یا حتی ممکن است 500 میلیون خط باشند که هر کدام از آنها به سیستم رایانهای میگویند که کار کوچکی را انجام دهد. این کار هر چند کوچک کاملاً مشخص است، مثلاً «10 را بر 2 تقسیم کن». به همین دلیل است که برنامهنویسی جذاب است چون به وسیله آن میتوان یک مسئله بزرگ را به اجزای کوچکتر تقسیم کرد و شروع به ساخت همه چیز از صفر کرد. این وضعیت ممکن است کمی انتزاعی باشد. در ادامه مثالی از یک نمونه کوچک برنامهنویسی در زندگی روزمره را بررسی میکنیم.
تصور کنید در خانهتان تنها هستید و احساس گرسنگی میکنید و آشپزی هم بلد نیستید. ناگهان به خاطر میآورید که یک بسته نودل در آشپزخانه دارید، بنابراین با مادر خود تماس گرفته و از وی میپرسید که چگونه میتوانید آن نودل را درست کنید. مادرتان یک راهنمای گام به گام در مورد روش پخت نودل به شما ارائه میکند.
بنابراین همان طور که میبینید آشپزی یک سفر است که از نقطه (الف) یعنی باز کردن بسته نودل آغاز و به نقطه (ب) که ریختن آن در قابلمه است میرسد. باید از مادرتان متشکر باشید که این فرایند را به چنین گامهای کوچکی تجزیه کرده است تا بتوانید سریعتر آن را درک کنید. اینک همان طور که قبلاً متوجه شدهاید، توالی مراحل نیز نقشی حیاتی دارد، اگر قبل از آن که قابلمه را روی اجاق گاز قرار دهید، نودل ها را روی آن بریزید، چیزی که به دست میآید، کاملاً متفاوت خواهد بود!
بدین ترتیب در برنامهنویسی نیز، مراحل مورد نیاز برای انجام کار مورد نظرمان را به رایانه میدهیم. در این روش یک مسئله پیچیده به دستورالعملهای منفرد کاملاً کوچکی تقسیم میشود و سپس با استفاده از زبان برنامهنویسی این دستورالعملها نوشته میشوند. زبان برنامهنویسی نیز مانند زبان مکالمه روزمره ما دستورزبانی دارد که باید رعایت شود تا رایانه درک کند که باید دقیقاً چه کاری باید انجام دهد. همان طور که در زبان معمولی، جمله داریم، در زبان برنامهنویسی هم «گزاره» (statement) وجود دارد. با این که این گزارهها ممکن است کلیدواژه و ساختار متفاوتی در زبانهای متفاوت داشته باشند؛ اما مفاهیم اساسی تشکیل دهنده برنامهنویسی، مشابه هستند. درک قواعد یک زبان خاص به این معنی است که دستور زبان آن زبان برنامهنویسی را میآموزیم. زمانی که مبانی زبان برنامهنویسی را آموختید، زبانهای برنامهنویسی دیگر را نیز راحتتر فرامیگیرید.
اینک سؤال این است که چرا باید این همه زبان برنامهنویسی مختلف وجود داشته باشد؟ آیا امکان این نبود که یک زبان ساده وجود میداشت؟ واقعیت این است که این زبان منفرد وجود دارد و زبان ماشین نام دارد، اما به هیچ وجه ساده نیست. حتی اگر درک کنیم که چگونه به زبان ماشین برنامهنویسی کنیم، برای انواع مختلف CPU-ها به برنامههای متفاوتی نیاز خواهیم داشت. در ادامه تصویری را مشاهده میکنید که انواع متفاوتی از زبانها را نمایش میدهد. این زبانها هر چه قدر به CPU نزدیکتر باشند، درک آنها برای انسان دشوارتر است و برعکس.
زبان دارت (Dart) چیست؟
تصور کنید از شما خواسته شده است که یک اپلیکیشن تجارت آنلاین برای یک مشتری بنویسید که BestBikes نام دارد. این اپلیکیشن ساده برای خرید و فروش دوچرخههای دست دوم است. کلاینت از شما یک وب اپلیکیشن برای مشتریان و یک اپ موبایلی برای فروشنده میخواهد. وب اپلیکیشن بخش عمده پروژه است، اما اپلیکیشن موبایل چنین نیست و صرفاً به فروشنده امکان میدهد که تصاویری از دوچرخه خود تهیه کرده و روی سرور بارگذاری کند. بنابراین احتمالاً تصمیم میگیرید برای این بخش از Flutter استفاده کنید.
فلاتر یک فریمورک توسعه موبایل است که از سوی گوگل توسعه یافته و از دارت به عنوان زبان برنامهنویسی بهره میگیرد. فلاتر برای ساخت نمونههای اولیه بسیار سریع است. از آنجا که اغلب برنامهنویسان این حوزه با جاوا و جاوا اسکریپت آشنا هستند، بادگیری دارت برای آنها بسیار آسان خواهد بود. استفاده از دارت آسان و یادگیری آن به سرعت امکانپذیر است و از این نظر شباهتی به زبانهای دیگر مانند سی شارپ یا جاوا ندارد. به باور بسیاری از افراد دارت آینده توسعه چند پلتفرمی را تصاحب خواهد کرد، چون به وسیله آن میتوان اپلیکیشنهای وب، موبایل و حتی سمت سرور را برنامهنویسی کرد.
ساختار اصلی
یکی از مهمترین نکاتی که وجود دارد این است که ما باید کد منبع خود را به کد ماشین تبدیل کنیم تا رایانه بتواند آن را بفهمد. البته لازم نیست شما همه این مراحل را بدانید؛ اما اگر میخواهید برنامهنویس بهتری باشید، دانستن آنها مورد نیاز خواهد بود. در ابتدا دارت را روی رایانه خود نصب میکنیم. به این منظور بهتر است به مستندات رسمی دارت (+) مراجعه کنیم چون بهروزتر است و روش آسانتری را پیشنهاد میکند. زبانهای برنامهنویسی به زبان سادهای نوشته میشوند و از این رو میتوانید یک ویرایشگر متنی ساده را باز کرده و شروع به نوشتن برنامه خود بکنید. دقت کنید که فایلهای دارت دارای پسوند فایلی به صورت dart. هستند.
در ادامه یک برنامه ساده Hello World را میبینید که ازنظر فنی یک برنامه کامل دارت محسوب میشود.
1// main() is the entry point of our dart program
2main() {
3 //print function to print the text to console
4 print("Hello World");
5}
این قطعه کد کوچک کاملاً گویا است. اجرای یک برنامه دارت از جایی آغاز میشود که تابعی به نام ()main نام دارد.
متغیرها و انواع داده
در هر برنامهای که مینویسیم باید تغییرات برخی از اطلاعات را ردگیری کنیم. برای نمونه در یک بازی ساده Flappy Bird باید امتیاز بازیکن کنونی، بالاترین امتیاز و مواردی از این دست را ذخیره کنیم. اینها بخشهای داده سادهای هستند که باید برای ذخیرهسازیشان متغیرهایی بسازیم. متغیرها در واقع بخشهایی از حافظه هستند که در سیستم نگهداری میشوند و نام خاصی به آنها میدهیم تا بتوانیم در مراجعات بعدی آنها را راحتتر پیدا کنیم و سپس در صورت نیاز مقدار ذخیره شده در آنها را تغییر میدهیم.
اصطلاح دیگری نیز وجود دارد که باید بشناسیم و آن «نوع داده» (datatype) است. منظور از نوع داده در واقع نوع قالب مورد نیاز برای ذخیرهسازی یک داده است. برخی موارد از انواع داده رایج شامل عدد صحیح، عدد اعشاری، رشته و آرایه است. انواع داده مختلف میتوانند مانند تاریخ، مقادیر بولی و مقادیر زمان سپری شده کاملاً اختصاصی باشند. با این وجود انواع داده در دارت همگی شیء هستند و از این رو مقدار اولیه آنها به صورت پیشفرض null یعنی صفر است. ما در ادامه به این موضوع بیشتر خواهیم پرداخت. در این بخش اقدام به ساخت چند متغیر میکنیم و روش استفاده از آنها را مورد بررسی قرار میدهیم. دارت پشتیبانی خاصی از انواع داده زیر دارد:
- عدد (شامل int و نوع داده double)
- رشته
- بولی
- لیست (که آرایه نیز نامیده میشود)
- نگاشت
- Runes (برای بیان کاراکترهای یونیکد در رشته)
- نماد
نکته: دارت یک زبان با تعیین نوع صریح است، یعنی تضمین میکند که یک متغیر با نوع خاص، نمیتواند مقداری از نوع دیگر را تولید کند.
1main(){
2 // It is inferred as integer automatically at runtime
3 var age = 10;
4 // OR
5 int age = 10;
6 int hexaValue = 0xEADEEAE;
7 double percentage = 13.0;
8 bool isStudent = true;
9}
در ادامه مواردی که در قطعه کد فوق آمدهاند را توضیح میدهیم.
- در دارت از علامت // برای درج کامنت های تکخطی استفاده میکنیم. کامنتها در واقع نکات مفیدی هستند که برای توجه برنامهنویسان در کد نوشته میشوند. این توضیحات در برنامه نهایی اجرا نخواهند شد.
- 10 یک عدد است. Sharad Ghimire یک رشته است. هر دو نوع گیومه یعنی '...' یا "..." در دارت پشتیبانی میشوند.
- int یک نوع داده عدد صحیح است و میتواند همه مقادیر اعداد صحیح که فاقد مقدار اعشاری هستند را در خود ذخیره کند.
- Var روشی برای اعلان یک متغیر بدون تعیین نوع آن است.
- ()main یک تابع خاص است که از سوی دارت ارائه شده و حضور آن ضروری است. این تابع سطح بالا جایی است که اپلیکیشنهای دارت شروع به کار میکنند.
- Bool یک نوع داده خاص بولی است که صرفاً میتواند شامل دو مقدار مختلف true و false باشد.
- کاراکتر ; یک نقطهویرگول است که خاتمه هر گزاره را اعلام میکند.
- ;var age = 10 برای ارزیابی مقدار موجود در سمت راست علامت تساوی و انتساب آن مقدار به آن چه در سمت چپ قرار دارد استفاده میشود.
1String s1 = 'Single Quotes';
2String s2 = "Double Quotes";
3String s3 = 'Hey! What\'s up?';
4//Long String
5String s4 = 'Lorem Ipsum is simply dummy text of the printing.'
6 'standard dummy text ever since the 1500s, when an'
7 'five centuries, but also the leap into electronic'
8 'remaining essentially unchanged.';
9// String Interpolation
10String name = 'Sharad';
11String message = 'My name is' + name;
12String messsage = 'My name is $name';
13String messsage = 'My name\'s length is ${name.length}';
- variable$ یا {expression}$ شامل عملیات درونیابی رشته است. یعنی مقدار رشتهای یک متغیر یا عبارت درون یک رشته دیگر جای میگیرد. منظور از «عبارت» (expression) صرفاً ترکیبی از یک یا چند متغیر، عملگر و تابع است که برای تولید رشته دیگر استفاده میشوند.
- 'What\'s’ به نام کاراکتر escape نامیده میشود. وقتی که یک گیومه تکی را درون یک شبه رشته با گیومه تکی مینویسیم از آن به وسیله \ استفاده میکنیم.
- در دارت مفهومی به نام تقدم عملگر وجود دارد، یعنی برخی از عملگرها مهمتر از بقیه هستند. برای نمونه * قبل از عملگر + محاسبه میشود که مشابه محاسبات ریاضیاتی است. برای این که مطمئن باشیم برخی عملگرها ابتدا محاسبه میشوند، میتوانیم از پرانتز نیز استفاده کنیم. برای نمونه در عبارت 2*(100 — 20) مقدار داخل پرانتز ابتدا محاسبه میشود.
- x += 10 به این معنی است که مقدار x هر چه قدر باشد، باید 10 واحد به آن اضافه شود. در واقع میانبری برای عبارت ;x = x + 10 است. در موارد مشابه میتوانیم از عملگرهای =+، =-، =*، =/ نیز استفاده کنیم.
- ++X در مواردی کاربرد دارد که بخواهیم 1 واحد به مقدار x اضافه کنیم، یعنی معادل با x += 1 یا x=x+1 است.
کار با کدهای شرطی
تا به اینجا ما تنها کدهای ساده تکخطی را نوشتهایم. در واقع همه کدهایی که نوشتهایم به سادگی به صورت خط به خط از بالا به پایین اجرا میشوند. اما اگر بخواهیم برخی کدها با توجه به برخی شرایط خاص اجرا شوند یا نشوند باید از ساختارهای شرطی کمک بگیریم. برای نمونه تصور کنید به مثال نودل اولیه خود بازگردیم. فرض کنید میخواهید نودلها را آماده کنید و به پیاز نیاز دارید. اما پیاز در منزل ندارید، آیا باید منتظر بمانید تا فردی پیاز تهیه کرده و برای شما بیاورد یا کلاً پیاز را نادیده بگیرید و به مرحله بعدی دستور آشپزی بروید؟
همان طور که میبینید گام بعدی که اجرا خواهد شد، به یک شرط وابسته است. در برنامهنویسی نیز موارد مختلفی وجود دارند که برخی محاسبات به شروطی وابسته هستند. برای نمونه اگر امتیاز کنونی بازیکن بالاتر از high score باشد، باید پیام «شما به بالاترین امتیاز دست یافتید» برای وی نمایش یابد. این مفهوم به نام برنامهنویسی شرطی شناخته میشود.
1void main() {
2 // If and else statement
3 var salary = 25000;
4 if (salary > 2000) {
5 print("Something");
6 } else {
7 print("Something else");
8 }
9}
در دستوری با ساختار { ... } (if (condition اگر این شرط برقرار باشد، در این صورت هر آنچه که بین دو آکولاد {} قرار دارد اجرا خواهد شد.
1// if else if statement
2var marks = 70;
3if(marks >= 90 && marks < 100){
4 print("Something");
5} else if(marks >= 80 && marks < 90){
6 print("Something eLse ");
7} else if(marks >= 70 && marks < 80){
8 print("Anything ");
9} else if(marks >= 60 && marks < 70){
10 print("Nothing");
11} else {
12 print("Invalid!");
13}
در کد فوق دستور شرطی دیگری به صورت زیر میبینید:
1if(condition1){
2...}
3else if (condition2) {
4...} else {
5...}
این ساختار به آن معنی است که اگر شرط اول یعنی condition1 برقرار باشد، بلوک اول کد اجرا میشود، اگر شرط دوم condition2 برقرار باشد، بلوک دوم کد اجرا میشود و اگر هر دو آنها نادرست باشند، بلوک آخر کد اجرا خواهد شد.
1int a = 2;
2int b = 3;
3a < b ? print(a) : print(b); // Prints a
4
5int smallNumber = a < b ? a : b;
6String name = null;
7String nameToPrint = name ?? "Guest User";
8print(nameToPrint); // Prints "Guest User";
یک ساختار شرطی دیگر نیز وجود دارد که به نام ساختار شرطی سهگانه مشهور است و فرم کلی آن چنین است:
1condition? exp1: exp2
اگر شرط مورد نظر برقرار باشد، مقدار exp1 ارزیابی شده و مقدار آن بازگشت مییابد؛ در غیر این صورت مقدار exp2 ارزیابی شده و بازگشت مییابد.
در ساختار exp1?? exp2، اگر exp1 غیر تهی باشد، مقدار آن بازگشت مییابد؛ در غیر این صورت ارزیابی شده و مقدار exp2 بازگشت مییابد.
1void main() {
2 String name = 'Sharad';
3 switch (name) {
4 case: 'Sharad':
5 print("You are Sharad!");
6 break;
7
8 case: 'Pramish':
9 print("You are Pramish!");
10 break;
11
12 default:
13 print("Your name is not in my system!");
14 }
15}
در برخی موارد ممکن است موقعیت خاصی وجود داشته باشد که در آن لازم نباشد یک شرط بررسی شود؛ بلکه کافی است مقدار یک متغیر را مورد بررسی قرار دهیم. این کار با استفاده از شرط else میسر است؛ اما در صورتی که تعداد بازههای مقادیر زیاد باشد، این دستور به سرعت طولانی میشود. در این موارد میتوان از switch case استفاده کرد که جایگزین بهتری محسوب میشود.
نوشتن گزارههای کنترل
فرض کنید میخواهیم برنامه سادهای بنویسیم که نام کاربر جاری را نمایش دهد. در ادامه متوجه میشویم که این کار را باید یک بار دیگر نیز انجام دهیم. شاید در ادامه متوجه شویم که این کار را باید 100 بار دیگر نیز در برنامه خود تکرار کنیم. در این موارد چه باید کرد؟ آیا باید آن خط کد را 100 بار کپی کنیم؟ در این موقعیتها، باید از گزارههای کنترل بهره بگیریم. گزارههای کنترل از سوی افراد مختلف به نام حلقه یا تکرار نیز نامیده میشوند. همه حلقهها شرطی دارند که مدت اجرای حلقه و زمان توقف آن را کنترل میکند.
1/// Do loop
2int value;
3int init = 1;
4int max = 5;
5value = init;
6
7do {
8 print value;
9 value++;
10} while (value < max);
11// 1 2 3 4
12
13// While Loop
14while(value <= max){
15 print value;
16 value++;
17}
18// 1 2 3 4 5
19// Infinite Loop
20do {
21 print('Value');
22 value++;
23
24 if(value == 3){
25 print('value is 3');
26 continue; // Continue the loop
27 }
28
29 if(value > 5){
30 print('value is greater than 5');
31 break; // jumps out of the loop
32 }
33
34} while(true);
35
36// For Each
37List people = ['Sharad', 'Ram', 'Hari'];
38
39// Starting value, range, increment
40for(int i = 0; i < people.length; i++){
41 print("Person at ${i} is ${person[i]}");
42}
43
44people.forEach((String person) {
45 print(person);
46});
در کد فوق ساختار حلقهای به صورت زیر داریم:
1do{ ...} while(condition);
حلقه Do همواره ابتدا بلوک کد را اجرا میکند و سپس به بررسی شرط حلقه میپردازد؛ در حالی که در ساختار زیر:
1while(condition){ ... }
حلقه While ابتدا به بررسی شرط اجرای حلقه میپردازد و در صورت برقرار بودن شرط، بلوک کد را اجرا میکند. گزاره ;break موجب میشود که اجرای کد از حلقه خارج شود و در واقع حلقه را متوقف میکند. به طور عکس گزاره ;continue موجب میشود که اجرای حلقه تداوم یابد.
در قطعه کد فوق یک ساختار به صورت زیر نیز داریم:
1for(initilization; condition; incremnet){..}
این ساختار حلقهای است که یک مقدار آغازین، یک بازه یا شرط و یک متغیر افزایش یا کاهشی دارد. همچنین میتوان از ساختار forEach برای collection-ها استفاده کرد که در ادامه به توضیح آن پرداختهایم.
کد ماژولار
پس از نوشتن گزارهها و کد شرطی، کد ما به سرعت شروع به بزرگ شدن میکند و آن چنان شلوغ میشود که درک آن دشوار میگردد. بنابراین باید آن را به قطعههای کوچکتری تقسیم کنیم که در دارت تابع یا متد نامیده میشوند. این تابع یا متدها موجب میشوند که درک کد آسانتر شده و همچنین قابلیت استفاده مجدد پیدا کند.
تابع در واقع قطعه کدی است که درون آکولاد قرار میدهیم و سپس هر جایی از برنامه خود که خواستیم میتوانیم آن را فراخوانی کنیم. اگر بخواهیم تابع را تعریف کنیم، باید بگوییم که تابع به مجموعهای از گزارهها گفته میشود که با هم گروهبندی شدهاند تا یک عملیات خاص را اجرا کنند. همه تابعها در دارت یک مقدار بازگشت میدهند. اگر هیچ مقداری از تابع بازگشت نیابد گفته میشود که تابع مقدار null یا تهی بازمیگرداند. تعیین نوع بازگشتی تابع اختیاری است، اما بر اساس قراردادهای کدنویسی دارت توصیه شده است که نوع بازگشتی تابع حتماً تعیین شود.
1void main(){
2 print(findArea(4, 5));
3 findPerimeter(4,5);
4}
5int findPerimeter(int length, int breadth){ // Required Parameter
6 return length + breadth;
7}
8void findArea(int length, int breadth){
9 print(length * breadth);
10}
11findArea(int length, int breadth){
12 // By default, if no return value is specified, function
13 returns null
14}
- ()int findPerimeter
این یک تعریف تابع است که مقدار int بازگشت میدهد. اگر تابع هیچ چیزی بازگشت ندهد، میتوانیم از void به عنوان نوع بازگشتی استفاده کنیم. اگر لازم باشد این تابع را فراخوانی کنیم، میتوانیم نام تابع را به همراه پرانتز به صورت زیر بنویسیم:
1;()findPerimeter
که به معنی فراخوانی تابع است.
1void main(){
2 int rectArea = getArea(10, 5);
3 findPerimeter(4, 2);
4}
5
6void findPerimeter(int l, int b) => print("Perimeter: ${2*(l+b)}");
7int getArea(int l, int b) => l * b;
8// Anonymous Functions (internal functions)
9() { print('Hello'); } // Nothing happens because its not invoked
10List people = [ 'Sharad', 'Ghimire']; // We will cover List later
11people.forEach(print);
12people.forEach(() {
13 print(name);
14});
در تابعهای تکخطی میتوان از فلش استفاده کرد و کلیدواژه return و {} را نیز حذف کرد. بدین ترتیب یک تابع تک عبارتی خواهیم داشت.
«تابعهای بینام» (Anonymous Functions) تابعهایی هستند که به صورت دینامیک در زمان اجرا، اعلان میشوند. دلیل این که آنها را به صورت بینام میشناسیم، این است که مانند تابعهای معمولی دارای نام نیستند. اگر تابعی تنها یک بار استفاده شود یا تعداد دفعات اجرای محدودی داشته باشد، از نظر ساختاری سبکتر از تابع دارای نام خواهد بود. مثلاً وقتی که میخواهیم نام همه افراد را نمایش دهیم، استفاده از تابع بینام سبکتر خواهد بود.
دو نوع پارامتر در دارت وجود دارد که پارامترهای الزامی و پارامترهای اختیاری نام دارند. خود پارامترهای اختیاری بر سه نوع هستند که «پارامترهای موقعیتی اختیاری» (optional positional parameters)، «پارامترهای با نام اختیاری» (optional named parameters) و «پارامترهای پیشفرض اختیاری» (optional default parameters) نام دارند. پارامترهای با نام در صورتی که تعداد پارامترها زیاد باشد از بروز خطا جلوگیری میکنند.
1void main(){
2 printCities("Dang", "Tulsipur", "Ghorahi"); // Must have all 3 arg
3 printCountries("Nepal", "India"); // Will get null in s3
4 print(findVolume(2, h: 10, b: 3)); // Sequence does not matter
5 var result = findArea(length: 2);
6}
7
8// Required Parameters
9void printCities(String s1, String s2, String s3) => print("First: ${s1}, Second: ${s2}, Third: ${s3}");
10
11//Optional Parameters [parameter]
12void printCounties(String s1, String s2, [String s3]) => print("First: ${s1}, Second: ${s2}, Third: ${s3}");
13
14// Optional Named Parameter
15int findVolume(int l, {int b, int h}) => l * b * h;
16
17// Optional Default Parameter
18int findArea({int length, int breadth = 10}) => length * breadth;
کلکسیونها
از «کلکسیون» (collection) برای مرتبسازی مقادیر همانند متغیرها استفاده میشود؛ اما میتواند مقادیر مختلفی را ذخیره کند و همه این مقادیر در یک متغیر دارای نام میگنجند. این یک روش عالی برای نگهداری دادههایی است که با هم ارتباط دارند. برای نمونه نام کشورها، یا نژاد سگها و غیره را میتوان در کلکسیونها ذخیره کرد. در دارت، List و Set بخشی از کتابخانه مرکزی هستند و از این رو نیازی به ایمپورت کردن آنها نداریم. در مورد انواع دیگر باید آنها را از بستههای دیگر ایمپورت کنیم. مفهوم ایمپورت کردن را در ادامه توضیح خواهیم داد.
1import 'dart:collection';
2//enum
3enum colors { red, green , blue }
4main(List<String> arguments) {
5 print(colors.values); // [colors.red, colors.green, colors.blue]
6 print(colors.red);
7 List test = [1, 2, 3, 4]; // Fixed length list
8 print(test.length);
9 print(test[0]); // Gives item at index 0
10 print(test.elementAt(2)); //3
11
12 // Growable List of generic type
13 List things = new List();
14 things.add(1);
15 things.add('cats');
16 things.add(true);
17
18 List<int> numbers = new List<int>();
19 //new creates a new object in memory
20 numbers.add(1);
21
22 Set<int> numbers = new Set<int>();
23 numbers.add(1);
24 numbers.add(2);
25 numbers.add(1);
26 print(numbers); // [1, 2]
27
28 Queue items = new Queue();
29 items.add(1);
30 items.add(3);
31 items.add(2);
32 items.removeFirst();
33 items.removeLast();
34 print(items); // { 3 }
35
36
37 Map people = { 'firstname': 'Sharad', 'lastname': 'Ghimire' };
38 print(people.keys); // (firstname, lastname)
39 print(people.values); // (Sharad, Ghimire)
40 print(people['firstname']); // Sharad
41
42 Map<String, String> people = new Map<String, String>();
43 people.putIfAbsent('firstname', () => 'Sharad');
44}
Enum
Enum-ها در واقع لیستی از ثابتها هستند. زمانی که به یک لیست از پیش تعریف شده از مقادیر نیاز داشته باشیم از Enum–ها استفاده میکنیم. برای نمونه نامهای روزها، ماهها و غیره را میتوانیم در Enum ذخیره کنیم. در دارت نمیتوان یک Enum را درون تابع main قرار داد. Enum سادهترین نوع کلکسیون است.
List
List یک کلکسیون قابل اندیسگذاری از مقادیر با طول ثابت است. هر لیست دارای یک اندیس است که از 0 شروع میشود. دو نوع لیست وجود دارند که یکی دارای طول ثابت و دیگری با طولِ قابل افزایش است. به دستور زیر توجه کنید:
1List<int> numbers = new List<int>();
این دستور یک نوع متغیر ژنریک از نوع int میسازد. در واقع لیستی است که مقادیر int دارد.
Set
Set میتواند شامل مقادیر معینی باشد که هیچ ترتیب خاصی ندارند و مقدار تکراری نیز در آن جای نمیگیرد.
Queue
Queue میتواند مقادیر مرتب شده را ذخیره کند و اندیسی ندارد. عملیات حذف و اضافه در Queue از آغاز و انتها قابل انجام است. Queue بخشی از کلکسیون استاندارد نیست و باید آن را با دستور زیر ایمپورت کنیم:
1import 'dart:collection';
Map
Map میتواند جفتهای کلید/مقدار را در خود ذخیره کند. Map یا نگاشت از یک مجموعه از جفتهای (کلید، مقدار) تشکیل یافته است به طوری که هر کلید محتمل تنها یک بار در مجموعه ظاهر میشود. میتوان آیتمهایی را به نگاشت اضافه کرد و لازم نیست که اندیس آنها را بدانیم. به این منظور کافی است کلید آن را که میتواند از هر نوعی باشد بشناسیم.
نکته: لیست، پایهایترین و پراستفادهترین کلکسیون است و از این رو به طور گستردهای مورد استفاده قرار میگیرد. کلکسیونهای دیگر، موضوع مباحث پیشرفته هستند که در مقالات بعدی مجله فرادرس به آنها خواهیم پرداخت.
مدیریت خطا
زمانی که همه سازههای مقدماتی برنامهنویسی فوق را آموختید، باید با این واقعیت نیز مواجه شوید که کدهای شما قطعاً با مشکلاتی مواجه خواهند شد. بنابراین رویه کار چنین است که ابتدا چند خط کد مینویسیم، سپس آن را بررسی و خطاها را رفع میکنیم و سپس ادامه کد را مینویسیم. درک این حلقه برای هر برنامهنویسی، امری ضروری محسوب میشود. برخی سازهها وجود دارند که از سوی دارت ارائه شدهاند و میتوانند به ردگیری این خطاها و حل آنها کمک کنند.
مدیریت خطا یک موضوع پیشرفته برنامهنویسی است؛ اما برخی از مبانی اولیه آن را در این راهنمای مقدماتی مورد بررسی قرار میدهیم.
1// Error is a program failure
2// Exception are errors that can be handled
3
4int age;
5int years = 7;
6print(age * years); //Unhandled exception: NoSuchMethodError: The method '*' was called on null.
7// Try Catch Finally
8try {
9 int age;
10 int years = 7;
11 print(age * years);
12}
13on NoSuchMethodError { // Catch specific error
14 print(’Sorry thats not gonna happen’);
15}
16catch(e) {
17 print("There was an error: ${e.toString()}");
18}
19finally { // Clean up
20 print("Compete");
21}
22
23// Throwing Exception
24try {
25 int age;
26 int years = 7;
27 if(years != 7) throw new Exception(’Years must be 7’); // Custom exception
28 if(age == null) throw new NullThrowError();
29 print(age * dogyears);
30}
31on NullThrownError{
32 print("The value was null!!");
33}
34on NoSuchMethodError {
35 print(’Sorry no such method!’);
36}
37catch(e) {
38 print("There was an error: ${e.toString()}");
39}
40finally {
41 print("Complete");
42}
یک کاربرد مجموعه try ،catch و finally، به دست آوردن و استفاده از منابعی از پایگاه داده در یک بلوک try و مدیریت استثناهای رخ داده مانند خطای شبکه یا عدم دسترسی در بلوک catch است. همچنین منابع کسب شده در بلوک final آزاد میشوند. مثلاً اتصال پایگاه داده بسته میشود. همچنین میتوانیم استثناهای خاص را به وسیله کلیدواژه on به دام بیندازیم.
سخن پایانی
شما با مطالعه کامل این راهنما اینک یک برنامهنویس هر چند مبتدی «دارت» محسوب میشوید. این مطلب قسمت اول یک سری سهگانه از مطالب راهنمای دارت است. در بخش دوم این راهنما به بررسی عمیقتر کلاسها و ژنریکها و همچنین سیستمهای فایل میپردازیم. در نهایت در بخش آخر این راهنما برنامهنویسی ناهمگام، برنامهنویسی تابعی، برنامهنویسی واکنشی، برنامهنویسی پایگاه داده و موارد دیگر را مورد بررسی قرار خواهیم داد:
اگر این نوشته برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای برنامهنویسی
- مجموعه آموزشهای برنامهنویسی اندروید
- مجموعه آموزشهای مهندسی نرمافزار
- مفاهیم مقدماتی فلاتر (Flutter) — به زبان ساده
- آموزش گوگل فلاتر (Flutter ): ساخت اپلیکیشن دستورهای آشپزی
- گوگل فلاتر (Flutter) از صفر تا صد — ساخت اپلیکیشن به کمک ویجت
==
به شدت استفاده کردم و راهمو اصلاح کرد ، فقط تشکر