Enums در Solidity سالیدتی

سلام، ممکنه در حین یادگیری زبان برنامه نویسی Solidity و یا توسعه قرارداد های هوشمند، اصطلاح Enums به گوشتون خورده باشه و کنجکاو شده باشید، اگر علاقه دارید بیشتر در مورد Enum ها در سالیدتی بدونید،‌ تا آخر این مقاله آموزشی همراه من باشید!

آرین حسینی - Arian Hosseini - مفهوم Enums در Solidity - مفهوم Enum ها در سالیدتی
آرین حسینی - Arian Hosseini - مفهوم Enums در Solidity - مفهوم Enum ها در سالیدتی

Enum ها چی هستند و چه کاربردی دارند؟

کلمه Enum در زبان انگلیسی مخفف Enumeration هست و به زبان خیلی ساده،‌ Enum ها به شما این امکان رو میدن که برای متغیر هاتون، مقادیر از پیش تعریف شده (predefined values) ایجاد کنید،

یعنی یک متغیر رو فقط محدود به داشتن یکسری مقادیر خاص و از پیش‌تعریف شده بکنید،

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

به صورت فنی،‌ شما یک Enum رو تعریف میکنید و یک لیست مشخصی از مقادیری که میخواید همیشه ثابت باشه رو مینویسید که بهشون میگیم Member یا اعضای اون Enum، بعد میتونید یک variable تعریف کنید از نوع اون Enum به خصوص که ساخته بودید، درواقع data type اون متغیر رو شما به جای string, boolean و... برابر با enumی که ساخته بودید، قرار میدید و دیگه اون متغیر فقط محدود به داشتن یکی از اون Member ها یا مقادیر از پیش‌تعریف شده‌ میشه،

جلوتر مثال هایی رو باهم میبینیم و کامل درک خواهید کرد، نگران نباشید!

ساختار تعریف یک enum در سالیدتی به شکل زیر هست:

enum <enumName>  { member1, member2, member3, ... }

نکته: شما میتونید enum ها رو حتی خارج از بلاک کد یک contract و یا library هم تعریف کنید.

همونطور که مشاهده میکنید، ساختار تعریف یک enum بسیار ساده هست، با کلمه کلیدی enum همراه با یک نام تعریف میشن و بعد داخل { ... } تمامی مقادیر دلخواه‌‌تون رو تعریف میکنید که ما به عنوان یک Member می‌شناسیم، همچنین نیازی به قراردادن سمی کالن ; هم نیست!

بریم چندتا Enum واقعی رو با هم ببینیم:

enum Color { BLUE, GREEN, RED }
enum LightMode { OFF, ON }
enum frenchFriesSize { LARGE, MEDIUM, SMALL }
enum Status { Finished, Pending, Failed }

مثلا frenchFries (سیب زمینی سرخ کرده) رو در نظر بگیرید، اینطور تصور کنید که شما میخواید سفارش سیب‌زمینی سرخ کرده بگیرید، حالا میخواید سه تا اندازه و سایز مشخص برای french fries ها تون مشخص بکنید و اجازه ندید مشتری هر سایزی که میخواد بخره، پس شما میاید حق انتخاب و گزینه های مشتری رو محدود میکنید فقط به سه گزینه Large, Medium, Small که میتونه فقط از بین این موارد یکی رو انتخاب کنه و سفارش بده.

یا مثلا به مثال دوم LightMode توجه کنید، در دنیای واقعی کلید روشن و خاموش کردن لامپ ها، ۲ حالت بیشتر نداره، یا چراغ خاموشه یا روشنه! شما نمیخواید این وسط کلی حالت دیگه هم وجود داشته باشه، درنتیجه اینجا از enum ها استفاده میکنید که میگید چراغ یا میتونه ON باشه یا OFF، حالت دیگری نداریم.

اینها‌ صرفا چندتا مثال بودن که مفهوم Enums رو بهتر درک کنید.

پس تا الان متوجه شدید که Enum ها صرفا یک متغیر رو محدود به داشتن یکسری مقادیر از پیش‌تعریف شده و ثابت میکنند و اون متغیر هر مقداری نمیتونه داشته باشه. (مثال لامپ ها:‌ یا ON یا OFF، تمام!)

نحوه استفاده از Enum ها در سالیدتی

خب بعد از اینکه شما یک enum رو تعریف کردید،‌ میخواید یک متغیر از نوع (data type) اون enum بسازید، (چون با توجه توضیحات بالا میدونید دیگه enum ها به تنهایی کار خاصی نمیکنند)

همونطور که احتمالا در جریان هستید، Solidity یک زبان برنامه نویسی statically-typed هست، به این معنا که حین تعریف یک متغیر شما باید Data Type اون مقداری که قرار داخل متغیر ذخیره بشه رو از قبل تعیین کنید،‌ به طور مثال اگر قراره داخل متغیر name شما یک string ذخیره کنید، باید دیتا تایپ اون متغیر رو از قبل برابر با یک string قرار بدید؛

حالا اگر شما بخواید داخل یک متغیر از مقادیر پیش‌فرض یک enum استفاده کنید،‌ قاعدتا نیاز دارید از قبل نوع اون متغیر رو برابر با نام enumی که تعریف کرده بودید، قرار بدید، به مثال زیر توجه کنید:

contract Arian {
    enum Color { Red, Blue, Green }
    
    Color myFavoriteColor = Color.Blue;
}

در اسمارت کانترکت بالا، من یک متغیر ساختم با نام myFavoriteColor که قرار مقدار رنگ مورد‌علاقم رو داخلشم ذخیره کنم، همچنین من از enum ها استفاده کردم چون به طور مثال داخل این کانترکت فقط میخوام همین ۳ تا رنگ موجود باشه و باهاش کار کنم (محدود کردم به استفاده از همین ۳ گزینه)

حالا چطور باید به Member ها یا آیتم های یک Enum دسترسی داشت؟

خیلی ساده شما فقط کافیه بعد از نام enumتون و دات (نقطه)، اسم آیتم رو بنویسید.

پس من یک متغیر تعریف کردم با نام myFavoriteColor و مقدار Color.Blue رو داخلش ذخیره کردم، خب حالا آیا میتونم دیتا تایپ این متغیر رو بزارم string؟‌ یا int؟ مشخصه که نه! چرا؟ چون من یک enum داخلش ذخیره کردم پس نوع داده این متغیر باید Color باشه، دقیقا نام همون enumی که ساخته بودم.

دقت کنید که Member های Enum شما نمیتونن دیتا تایپ هایی مثل string یا boolean و یا uint باشند، اگر هم چند کلمه‌ای بودن باید با underscore (_) اون هارو تعریف کنید، درغیر این صورت به ارور برمیخورید.

خیلی راحت بود، نه؟!

نکته: Solidity در پشت صحنه (یا به قول انگلیسی ها under the hood)، میاد و enum ها رو به unsigned integer یا uint تبدیل میکنه.

جلو تر متوجه خواهید شد، این نکته یعنی چی.

حالا شما میتونید به همین روش، فانکشن هایی رو تعریف کنید که با این enum ها کار میکنند، مقادیرشون رو تغییر میدن، یا return میکنند،

به مثال انتخابات آمریکا توجه کنید :)

https://gist.github.com/RyanHosseini/af42aa3c1ca7117183206d2edead65bc

خب، یک Smart Contract ساختم با نام USAElection که میخوایم‌ داخلش کامل Enum ها رو یاد بگیریم و باهاشون حسابی کارکنیم،

داخل این قرارداد هوشمند من یک enum تعریف کردم با نام Candidates که قرار لیست نامزد های انتخابی ریاست جمهوری ایالات متحده آمریکا رو داخلش از پیش‌ تعریف کنیم و به افراد رای دهنده بگیم، آقا کلا ۳ تا نفر کاندید ریاست جمهوری هستند، از بین این ۳ تا میتونی یکی رو بهش رای بدی، همینطوری نیست که بری دست یکی رو بگیری بیاری و بگی من میخوام ایشون رییس جمهور باشه، کامل جا افتاد؟ ?

کاندید ها کیا هستند؟‌ ایلان ماسک، جو بایدن، دانلد ترامپ

نکته حاشیه‌ای: ایلان ماسک نمیتونه رئیس جمهور آمریکا بشه، به این دلیل که در آمریکا متولد نشده، حالا ما اینجا صرفا مثال آموزشی زدیم، درگیرش نشید! ?

خب حالا من چند تا متغیر تعریف کردم با نام myChoice که کاندید محبوب و مدنظر من هست، AshkanChoice که کاندید دوستم اشکان، VahidChoice کاندید مدنظر وحید و ArminChoice انتخاب آرمین هست، همچنین یک currentPresident هم داریم که از نوع constant هم تعریف شده و رئیس جمهور فعلی رو شامل میشه.

نکته:‌ زمانی که شما برای یک متغیر از کلمه کلیدی constant به معنای ثابت استفاده میکنید،‌ مقدار اون متغیر در ادامه کد ها و برنامه‌تون نمیتونه تغییر کنه، صرفا همون مقداری همیشه خواهد بود که اول براش تعریف کردید و در واقع همیشه ثابت هست.

خیلی هم عالی، کاندید های مدنظر آرمین، اشکان و وحید رو که از قبل مشخص کردیم، سه تا فانکشن با نام های setElonMusk, setJoeBiden, setDonaldTrump هم تعریف کردم که قراره مقدار myChoice (انتخاب من) رو تغییر بدن، یعنی من هرکدوم رو call کنم، کاندید مدنظر من تغییر میکنه،

مثلا اگر من تابع setElonMusk رو صدا بزنم، مقدار myChoice میشه Candidates.ELON_MUSK.

همچنین همونطور که مشاهده میکنید، یک فانکشن دیگه هم وجود داره با نام setMyChoice که از شما یک id میگیره و بسته به اون id، مقدار enum متغیر myChoice رو تغییر میده، اگر صفر رو پاس بدید، myChoice میشه Joe Biden، اگر ۲ رو پاس بدید، تغییر میکنه به ایلان ماسک و به همین ترتیب، اگر هم آی دی‌ای رو پاس بدید که وجود نداره، مقدار برابر میشه با currentPresident یا رئیس جمهور فعلی که در اینجا برای مثال آقای دانلد ترامپ هست،

فانکشن دیگری که ما داریم، getMyChoice هست که میبینید مقدار بازگشتیش (returns) برابر با Candidates هست، یعنی قرار یک enum با نام Candidates ریترن کنه،

در واقع الان سالیدیتی، Candidates رو یک DATA TYPE می‌شناسه، شما میتونید با این نوع داده، یک متغیر تعریف کنید، یا برای یک فانکشن مشخص کنید که قرار یک مقدار از نوع Candidates برگردونه!

❌ پس دقت داشته باشید در قسمت (.......) returns تابع شما به هیچ عنوان نمیتونید بنویسید ```returns (enum)``` و به جاش باید نام اون enum رو قرار بدید.

اگر تابع getMyChoice رو کال کنید، میبینید که بهتون یک عدد برمیگردونه و نه مقدار ایلان ماسک و...، چرا؟ دلیلش چیه؟ دلیلش این هست که همونطور که بالاتر اشاره کردم، سالیدتی در پشت صحنه، enum ها رو به یک uint تبدیل میکنه،

در نتیجه شما اگر مقدار myChoice رو return کنید،‌ صرفا index اون آیتم یا ممبر رو داخل enum بهتون نشون میده (دقیقا مشابه index در آرایه ها)

به طور مثال، اگر مقدار Elon Musk باشه، به شما ایندکس 2 رو نشون میده، درسته؟ Joe Biden ایندکس شماره صفر هست در نتیجه بعدی 1 و ایلان ماسک میشه 2.

در نهایت، داخل تابع getArminChoice که قرار کاندید مدنظر آرمین رو برگردونه هم میبینید که ما اومدیم enum رو تبدیل به یک uint کردیم و بعد return کردیم که بازم فرقی نمیکنه، چون درنهایت شما Member های اون enum رو به صورت یک uint میبینید، این رو صرفا خواستم دیده باشید.


نتیجه گیری نهایی:

Enum ها در سالیدتی بسیار سادست و با چندبار تمرین کردن و مثال زدن برای خودتون، قطعا به خوبی بهش مسلط خواهید شد.

امیدوارم که این مقاله آموزشی بهتون در درک مفهوم Enum ها کمک کرده باشه! خوشحال میشم نظراتتون رو بدونم، قطعا این مقاله به مرور زمان به کمک شما عزیزان تکمیل تر و اشکالاتش رفع خواهد شد!

مرسی از اینکه تا آخر با من همراه بودید! ☕