Dart Const (const values)

Flutter Challenge(چالش فلاتر)

قسمت قبلی : بررسی مفهوم const در کلاس (static const).

?قبل از پرداختن به مفهوم const constructor ها , یکم در مورد const values صحبت میکنیم تا درک const constructor ها هم واسمون راحتر بشه.

باز هم میریم سراغ داکیومنت و چنتا جمله ای که جلسه اول با هم خوندیم رو مجددن مرور میکنیم.

The const keyword isn’t just for declaring constant variables. You can also use it to create constant values, as well as to declare constructors that create constant values. Any variable can have a constant value
کلید واژه const فقط برای تعریف متغیر های ثابت نیست.شما میتونید از این کلید واژه برای ایجاد مقادیر ثابت (values) و همچنین سازنده هایی که مقادیر ثابت رو ایجاد میکنند استفاده کنید.(منظورش اینه فقط قبل اسم متغیر نمیاد بلکه میتونه قبل اسم سازنده یا قبل مقدار هم بیاد.)
var foo = const [];
final bar = const [];
const baz = []; // Equivalent to `const []`
You can’t change the value of a const variable:
baz = [42]; // Error: Constant variables can't be assigned a value.
You can change the value of a non-final, non-const variable, even if it used to have a const value:
foo = [1, 2, 3]; // Was const []

تا اینجا هر چی با const کار کرده بودیم این کلید رو قبل اسم متغیر میوردیم ولی توی این مثال ها میبینیم که بعضی جاها قبل مقدار (value) اومده یا حتا قبل اسم متغیر final اومده و قبل مقدارش const.

خب پس ببینیم چنتا حالت مختلف داریم و هر کدوم رو تحلیل کنیم.

  • کلید final فقط میتونه قبل اسم متغیر بیاد و قبل مقدارش نمیتونه بیاد.
  • کلید const هم میتونه قبل اسم متغیر بیاد و هم قبل مقدارش.

پس :

  • حالت اول : نه قبل اسم متغیر و نه قبل مقدارش هیچی نیاد.
var names = ['Mohammad' , 'Arash'];
  • حالت دوم : قبل اسم متغیر final بیاد و قبل مقدارش هیچی نیاد.
final names = ['Mohammad' , 'Arash'];
  • حالت سوم : قبل اسم متغیر final بیاد و قبل مقدارش const بیاد .
final names = const  ['Mohammad' , 'Arash'];
  • حالت چهارم: قبل اسم متغیر const بیاد و قبل مقدارش هیچی نیاد یا قبل هر دو const بیاد (این دو حالت معادل هم هستن , یعنی وقتی قبل اسم متغیر const میاد به صورت ضمنی انگار که قبل مقدارش هم const گذاشتی)
const names = const  ['Mohammad' , 'Arash'];
//or
const names =  ['Mohammad' , 'Arash'];
  • حالت پنجم: قبل اسم متغیر هیچی نیاد ولی قبل مقدارش const بیاد.
var names = const  ['Mohammad' , 'Arash'];

حالا به جای اینکه بهتون بگم دونه دونه توی این حالات چه بلایی سر کدمون میاد تحلیل کردن رو یادتون میدم و بعدش که خودتون فکر کردید و تحلیل کردید با هم همه حالتها رو تحلیل میکنیم.???


✅قبل از این گفتیم که اگه یه متغیر رو final کنیم اون متغیر فقط و فقط یکبار میتونه مقدار بگیره و ثابت هست ولی این مقدار گرفتن توی run-time و وقتی که اجرای کد به اون نقطه رسید انجام میشه.

✅همچنین گفتیم که اگه یه متغیری رو const کنیم اون هم فقط و فقط یکبار میتونه مقدار بگیره و ثابت هست با این تفاوت که اینبار مفدار گرفتن توی compile-time انجام میشه و این متغیر ها یا بهتره بگیم ثابتها قبل رسیدن کد به مرحله اجرا مقدارشون رو گرفتن و حاضر و اماده هستن.

✅الان هم که گفتیم کلید const علاوه بر قبل اسم متغیر قبل مقدار یا value هم میتونه بیاد.

✅قبلن هم گفتیم که اگه قبل یه چیزی const بیاد اون تکه از کد توی زمان کامپایل تجزیه و تحلیل میشه و مقدارش ثبت میشه.

✅همچنین گفته بودیم که وقتی که قبل اسم یه متغیر const میاد کل عبارت یعنی طرف چپ و راست توی زمان کامپایل رصد میشن و الان هم توی حالت چهارم گفتیم که وقتی قبل اسم متغیر const میاد انگار قبل مقدارش هم const گذاشتی , پس به همین علته که وقتی قبل اسم متغیر const میاد کل عبارت توی زمان کامپایل رصد میشه.

❓گفتیم اگه قبل اسم متغیر const بیاد اون متغیر توی زمان کامپایل مقدارشو میگیره. خب حالا اگه قبل مقدار بیاد چی میشه؟

??در این حالت توی زمان کامپایل اون مقدار به عنوان یک مقدار یا value ثابت ثبت میشه و دیگه هر جایی از کد که از اون مقدار با پیشوند const استفاده کردی همون مقدار ثبت شده رو بهت میده.

مثال میزنیم:

دو تا آرایه دقیقن مثل هم تعریف کردیم و قبل اسم متعیر ها و مقادیر هیچی نیومده. و بعد اونها رو با هم مقایسه کردیم (==). میبینیم که نتیجه false شده.

❓چرا ؟‌

??چون که هر بار که از ['mohammad' , 'Arash'] استفاده میکنم . یعنی مینویسم :

var namesN = ['mohammad' , 'Arash'];

یه ارایه جدید توی حافظه برام ایجاد میکنه و وقتی که با == دو تا آرایه رو مقایسه میکنم بررسی میکنه که آیا این آرایه ها توی یک مکان از حافظه قرار دارن یا نه . و چون که توی مکان های مختلف از حافظه ایجاد شدن نتیجه رو false برمیگردونه.

حالا یه مثال دیگه :‌

اینبار قبل مقدار ها const گذاشتم و همون طور که میبینید نتیجه true بشد.

❓چرا؟

??چون که وقتی کامپایلر برای بار اول میرسه به const ['mohammad' , 'Arash'] این مقدار رو به عنوان یک مقدار ثابت ثبت میکنه و بعد از اون هر بار و هر کجا که به یک چنین عبارتی رسید دقیقن همون مقدار قبلی رو که واسش ثبت کرده دوباره استفاده میکنه.

یعنی وقتی کامپایلر رسید به

  var names = const ['mohammad' , 'Arash'];

یه مقدار ثابت برای ارایه مورد نظر ثبت میکنه.

حالا اینجا خود متغیر const نیست و قراره که توی run-time مقدار بگیره. توی run-time وقتی رسید به این خط از کد میگه من قبلن و زمان کامپایل برای این ارایه یه مقدار ثابت ثبت کردم و همون مقدار رو میریزم توی متغیر names . و بعدش هم وقتی میرسه به خط بعدی همین تحلیل رو میکنه و دوباره همون آرایه ثابت ثبت شده توی زمان کامپایل رو توی متغیر names2 هم میریزه و این میشه که هر دو متغیر دقیقن به یک مکان از حافظه اشاره میکنن و نتیجه مقایسه == برابر با true میشه.


مثال بعدی :

دو تا متغیر از نوع String تعریف کردم و هیچکدوم هم const نیستن ولی نتیجه مقایسه true شد!!!

❓این رو چطور تحلیل میکنید؟

قبلن و توی قسمت اول گفتیم که همه string literal ها , .... compile-time constants هستن.

❓یعنی چی ؟

یعنی وقتی میرسه به خط اول میبینه یه String تعریف شده و چون که String ها به صورت ضمنی const هستن یه مقدار (value) ثابت ('Mohammad') توی حافظه ایجاد میکنه و بعد از اون هر جای کد که نیاز به این مقدار باشه از همون مقدار اولیه ثبت شده توی حافظه استفاده میکنه.

پس وقتی که توی run-time به این کد ها رسید و خواست که به متغیر های name و name2 مقدار بده همون مقدار ثابت 'Mohammad' که زمان کامپایل ثبت شده بود رو میریزه داخلشون. پس این دو هم با هم برابر میشن.

اطلاعات عمومی: توی زبان های برنامه نویسی دیگه مثل JAVA به دیتا تایپ هایی مثل int , double , boolean , ... میگن Primitive Data Types.

در واقع اونجا دو نوع type داریم.

  • Primitive Data Type.
  • Reference Data Type.

که بلایی که سر Primitive ها میاد شبیه همین بلایی هست که اینجا سر String اومد که از توضیح بیشتر میگذریم. (البته توی JAVA تایپ String از نوع Primitive نیست ولی بلایی شبیه Primitive ها سرش میاد...بگذریم.)

این هم یه مثال دیگه:

که الان میفهمیم با توجه به مفهوم compile-time constants چرا این مقایسه مقدار true رو میده.


خب حالا وقتشه که بریم سر تحلیل حالات مختلفی که با هم مرور کردیم. (فقط قبلش یادتون نره خودتون فکر کنید...)

  • حالت اول : نه قبل اسم متغیر و نه قبل مقدارش هیچی نیاد.
var names = ['Mohammad' , 'Arash'];

خب توی این حالت که هیچ اتفاق خاصی نمیوفته. توی زمان کامپایل هیچ مقداری ثبت نمیشه و توی run-time یه ارایه جدید ایجاد میشه و ریخته میشه توی متغیر names .

میبینید که هر بلایی که بخوایم میتونیم سر names بیاریم.

چرا هر چی من میگم گیر نمیدید!!! من گفتم که توی این حالت در زمان کامپایل هیچی ثبت نمیشه!!! نباید هیچی بگید؟؟؟???

❓پس این 'Mohammad' و 'Arash' چی هستن؟

??درسته که خود آرایه یا متغیر از نوع const نیستن و زمان کامپایل ثبت نمیشن ولی این مقادیری String ای که باید ثبت بشن.

???خب دیگه خودتون استاد شدین و تحلیل این رو میسپارم به خودتون...???

  • حالت دوم : قبل اسم متغیر final بیاد و قبل مقدارش هیچی نیاد.
final names = ['Mohammad' , 'Arash'];

❓توی این حالت چه اتفاقی میوفته؟

خب واضحه که چون متغیر final هست فقط یکبار میتونه مقدار بگیره و دیگه نمیتونیم تغییرش بدیم و این ثبت مقدار هم توی run-time انجام میشه.

میبینید که اگه بخوایم دوباره بهش مقدار بدیم ارور میده.

سوال...

❓آیا در این حالت میتونیم خود لیست رو ویرایش کنیم ؟‌ یعنی یه ایتم بهش اضافه یا کم کنیم؟ یا ایتم هاش رو ویرایش کنیم؟

میبینیم که شد!!!

❓چرا؟ مگه متغیر رو final تعریف نکردیم ؟ پس چرا میتونیم لیست رو ویرایش کنیم؟???

??جواب: خود متغیر final هست و پس از یکبار مقدار دهی نمیتونیم دیگه تغییرش بدیم و اون رو برابر با یه مقدار دیگه قرار بدیم ولی خود مقدار یعنی ['Mohammad' , 'Arash'] یه مقدار ثابت نیست و چون که یه مقدار ثابت نیست و توی زمان کامپایل هم توی حافظه ثبت نشده امکان ویرایشش هست.

  • حالت سوم : قبل اسم متغیر final بیاد و قبل مقدارش const بیاد .
final names = const  ['Mohammad' , 'Arash'];

توی این حالت متغیرمون final هست و توی run-time مقدار دهی میشه و بعد از مقدار دهی امکان تغییرش نیست.

ولی مقدارش (value) از نوع const هست داره توی compile-time رصد میشه و ثبت میشه و وقتی که توی run-time کدمون میرسه به این نقطه مقداری که زمان کامپایل برای این value ثبت شده بود داخل متغیر قرار میگیره.

??پس اینجا دو تا اتفاق مهم میوفته...

  • اول اینکه چون متغیر final هست دیگه نمیتونیم اون رو برابر با یه مقدار جدید قرار بدیم.
  • و دوم اینکه چون مقدارش const هست امکان ویرایش (اضافه و کم کردن یا ویرایش ایتم ها ) وجود نداره.

به ارورهایی سمت چپ توجه کنید.

❓چرا این اتفاق افتاد؟

??چون که ما به کامپایلر گفتیم که یه لیست const با این مقادیر داریم . کامپایلر هم دقیقن اون رو ایجاد میکنه و هر جا لازم داشتیم همون رو بهمون میده و امکان ویرایش رو بهمون نمیده چون که اگه بتونیم ویرایش کنیم دیگ از مفهوم const بودن خارج میشه (این رو به عنوان مقدمه ای برای مبحث const constructor داشته باشین که اونجا خیلی مفصل راجبش صحبت کنیم.)

حالت چهارم: قبل اسم متغیر const بیاد و قبل مقدارش هیچی نیاد یا قبل هر دو const بیاد (این دو حالت معادل هم هستن , یعنی وقتی قبل اسم متغیر const میاد به صورت ضمنی انگار که قبل مقدارش هم const گذاشتی)

const names = const  ['Mohammad' , 'Arash']; 
//or 
const names =  ['Mohammad' , 'Arash'];

خب تحلیل این حالت هم خیلی باید واستون راحت باشه .

هم متغیر از نوع const هست و توی compile-time مقدار میگیره و هم مقدارش const هست و توی compile-time ثبت میشه.

پس نه میشه مقدار متغیر رو تغییر داد و نه میشه ویرایشش کرد.

حالا مثال زیر رو با توجه به توضیحات این جلسه و جلسات قبل خودت تحلیل کن...

و حالا این یکی ...

❓چرا اولی درسته و دومی غلط؟

حالت پنجم: قبل اسم متغیر هیچی نیاد ولی قبل مقدارش const بیاد.

var names = const  ['Mohammad' , 'Arash'];

❓توی این حالت چه اتفاقی میوفته؟

??خود متغیر توی run-time مقدار دهی میشه ولی مقدارش const هست و توی compile-time تکلیفش مشخص میشه.

پس میتونیم مقدار متغیر رو برابر با یه متغیر دیگه قرار بدیم:

ولی نمیتونیم ویرایشش کنیم:

ولی اگه مقدارش رو برابر با یه مقدار غیر const گذاشتیم امکان ویرایش هم هست:

???امیدوارم که از این جلسه لذت برده باشید.???


قسمت بعدی : بررسی مفهوم const در کلاس (const constructor).

برای دریافت آموزش های بیشتر و شرکت در چالش های فلاتری, کانال فلاتری Flutter Challenge(چالش فلاتر)رو دنبال کن.