Benyamin Abbasi
Benyamin Abbasi
خواندن ۱۱ دقیقه·۴ سال پیش

آموزش Solidity (بخش دوم) نوع و ساختار داده ها

قبل از اینکه شروع کنیم، نسخه سالیدیتی را در کد قرارداد هوشمند به روز رسانی کنید تا بتوانیم از امکانات آن استفاده کنیم. البته الان که این مطلب در حال نگارش است، نسخه 0.6.0 برای سالیدیت موجود است ولی ما با 0.5.1 کار می کنیم. لذا اولین خط را به شکل زیر تغییر دهید.

pragma solidity ^0.5.1;

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

اکنون، برای جلوگیری از برخی هشدارها در نسخه جدید سالدیتی، function مربوط به get() را به شکل زیر تغییر می دهیم:

function get() public view returns(string memory) { return value; }

همین تغییرات را برای function مربوط به set() هم انجام می دهیم:

function set(string memory _value) public { value = _value; }

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

در ابتدا، با state variable شروع می کنیم، سالیدتی امکانات خیلی خوبی برای این نوع از متغیر ارائه داده است. در ابتدا ما value را به state variable اختصاص می دهیم و از عملگر get() برای داده مقدار به آن استفاده می کنیم. سالیدیتی یک روش خیلی ساده برای این کار تعریف کرده که در زیر می بینید:

string public value;

این روش وضعیت متغیر را به صورت دسترسی public تعریف می کند و این اجازه را می دهد که از خارج از قرارداد هوشمند هم بتوان آن را به صورت دسترسی read بازخوانی کرد. در عمل سالیدیتی عملگر value() را خیلی سریع صدا کرده و دیگر نیازی به استفاده از get() نیست. برای همین خیلی راحت می توان state variable به شکل زیر تعریف کرد:

string public value = &quotmyValue&quot

عملا ما دیگر نیازی به استفاده از عملگر constructor هم نداریم، که باعث کاهش زمان و حجم کد نوشته شده خواهد شد. باز هم می توانیم با تعریف کردن متغیر به شکل ثابت از تغییرهای بعدی آن جلوگیری کنیم، مثل این حالت:

string public constant value = &quotmyValue&quot

اکنون، باید عملگر set()را حذف کنیم چرا که سالیدیتی به شما اجازه نمی دهد که در حالت constant روی آن تغییری ایجاد شود.

آنچه در بالا دیدید مروری بر خلاصه سازی بود که سالیدیتی ایجاد کرده و کار را ساده کرده است. اکنون می توان state variable ها را برای انواع دیگری از داده ها بررسی کنیم. همانطور که در حالت string دیدیم، ما می توانیم میزان عمومی یا visibility را به نام متغییر تخصیص دهیم. برای همین ما با ساختن یک متغیر boolean به شکل زیر شروع می کنیم:

bool public myBool = true;

این متغییر می تواند true یا false باشد.

اکنون یک متغیر عددی integer به شکل زیر می سازیم:

int public myInt = 1;

متغیر های عددی می توانند مثبت یا منفی باشند. اگر می خواهید اعداد حتما مثبت باشند، از روش زیر استفاده کنید:

uint public myUint = 1;

حتی ما می توانیم تعداد خاصی از بیت ها را برای اعداد در نظر بگیریم. در مثال بالا به صورت پیش فرض 256 بیت در نظر گرفته شده که به شکل زیر باز شده است:

uint256 public myUint256 = 9999;

شما می توانید به صورت 8 بیت هم آن را محدود کنید، مثل این:

uint8 public myUint8 = 8;

Enums

اکنون، بررسی کوتاهی روی ساختار داده سالیدیتی داشته باشیم. در ابتدا به ساختار داده Enum نگاه کنید، این ساختار داده روشی برای نگهداری لیست های تجمیع شده یا enumerated lists است. یک enum در قرارداد هوشمند به شکل زیر است:

enum State { Waiting, Ready, Active }

به طور مثال، این موضوع می تواند وضعیت active را در قرارداد هوشمند به شکل گزینه های Waiting, Ready, and Activeنشان دهد. ما می توانیم وضعیت فعلی قرارداد هوشمند را از طریق زیر چک کنیم:

State public state;

اکنون، می توانیم وضعیت پیش فرض در constructor را به شکل زیر تعریف کنیم:

constructor() public { state = State.Waiting; }

یا اینکه به حالت active تغییر دهیم:

function activate() public { state = State.Active; }

و در انتها، می توانیم لیست enum را چک کرده و ببینیم که آیا وضعیت قرارداد به صورت فعال است یا خیر؟

function isActive() public view returns(bool) { return state == State.Active; }

در این مرحله، قرارداد هوشمند ما باید به شکل زیر باشد:

pragma solidity 0.5.1; contract MyContract { enum State { Waiting, Ready, Active } State public state; constructor() public { state = State.Waiting; } function activate() public { state = State.Active; } function isActive() public view returns(bool) { return state == State.Active; } }

این یک مثال از روشی استفاده از enums بود که بررسی وضعیت را درون قرارداد هوشمند انجام می دهد.

در آینده در خصوص استفاده از این عملگر برای قراردادهای هوشمند برگزاری عرضه توکن اولیه یا ICO ها و وضعیت open یا closed آن بیشتر توضیح خواهم داد.

Structs

سالیدیتی به شما اجازه می دهد که ساختار داده خاص خودتان را به روش Structs بسازید و داشته باشید. به طور کلی شما هر نوع داده ای که بخواهید می توانید مدل کرده و با خاصیت های دلخواه و ترکیبی از انواع داده داشته باشید. یک نگاهی به این ساختار داشته باشیم و از مثال struct people استفاده می کنیم:

struct Person { string _firstName; string _lastName; }

خوب چه کاری کردیم؟ ما "فردی" را مدل کردیم که _firstNameو _lastNameدارد. دقت کنید که ما قادریم هر نوع داده ای که دوست داریم را وارد کنیم. ما از strings برای هر دو attribute استفاده کردیم. در عین حال می توانیم تا 17 ویژگی متفاوت را در اینجا برای هر نوع داده ای داشته باشیم. فعلا سعی کنیم همین طور ساده حفظ کرده و با همین مدل دو attribute برای فرد استفاده کنیم.

آرایه ها - Arrays

اکنون لازم است که محلی برای ذخیره سازی در این ساختار فرد داشته باشیم، برای همین ما از آرایه استفاده می کنیم. مثال people را به صورت آرایه ببینید:

Person[] public people;

دقت کردید که ما یک آرایه به نام people را برای people تعریف کردیم. علاوه بر این دسترسی خارجی را به شکل public قرار می دهیم و به وضعیت متغیر people آن را وصل می کنیم. این روش باعث ایجاد عملگری شده که به افراد درون آرایه دسترسی لازم را می دهد. این را باید اشاره می کردم، که بازخوانی عملگر
people()خارج از قرارداد هوشمند کل اطلاعات آرایه را برنمی گرداند. در عوض عملگر people() می تواند argument مثل index را قبول کرده و از این طریق به افراد داخل آرایه بر اساس اجازه دسترسی می دهد. دقت شود که این یک آرایه بر پایه صفر است. برای مثال ما برای دسترسی به اولین نفر در آرایه به این شکل بازخوانی می کنیم:

people(0)

اکنون، میتوانیم روشی بسازیم که "فرد" جدیدی به این آرایه اضافه کنیم. عملگر addPerson()را به شکل زیر تعریف می کنیم:

function addPerson(string memory _firstName, string memory _lastName) public { people.push(Person(_firstName, _lastName)); peopleCount += 1; }

این عملگر بر اساس ساختار ویژگی های person درخواست های جدیدی را قبول می کند و بعد از آن یک instantiate جدید برای ایجاد کرده و با استفاده از روش عملگر push به آرایه people اضافه می کند. علاوه بر این وضعیت peopleCount را هم به عدد 1 تغییر می دهد. می توانیم وضعیت متغیر را در قرارداد هوشمند به شکل زیر تعریف کنیم:

uint256 public peopleCount;

ما از این داده به عنوان cache شمارنده استفاده می کنیم. یادتون که گفتم شما نمی تونید کل آرایه peopleرا با استفاده از عملگر people()بازخوانی کنید؟ با این روش که بدانید چند نفر درون آرایه هستند، شاید بهتر بتوانیم از عملگر people() برای بازخوانی person استفاده کنیم.

خوب الان کد قرارداد هوشمند ما باید به شکل زیر باشد:

pragma solidity 0.5.1; contract MyContract { Person[] public people; uint256 public peopleCount; struct Person { string _firstName; string _lastName; } function addPerson(string memory _firstName, string memory _lastName) public { people.push(Person(_firstName, _lastName)); peopleCount += 1; } }

Mappings

سالیدیتی یک ساختار داده دیگر هم دارد که عنوان mapping دارد، این ساختار داده به شما اجازه ذخیره سازی زوج کلیدها را می دهد. این ساختار داده شبیه یک آرایه اشتراکی و یا یک جدول هش Hash table در دیگر عملگرها رفتار می کند. ما از mapping به شکل زیر میتوانیم استفاده کنیم:

mapping(uint => Person) public people;

این روش mapping را در ساختار person ذخیره می کندو جایگرین آرایه people که در مثال قبل استفاده کردیم. این کلید یک integer امضا نشده است و داده آن به عنوان struct در person استفاده می شود. نوع استفاده از این کلید دقیقا مثل id در پایگاه داده استفاده می کنیم. ما می توانیم struct را در person به شکل زیر به روزسانی و آپدیت کنیم:

struct Person { uint _id; string _firstName; string _lastName; }

اکنون میتوانیم عملگر addPerson()را برای به روز رسانی و mapping در people به شکل زیر استفاده کنیم:

function addPerson(string memory _firstName, string memory _lastName) public { peopleCount += 1; people[peopleCount] = Person(peopleCount, _firstName, _lastName); }

در این مرحله از cache شمارنده peopleCountبرای ساخت id برای person استفاده میکنیم. بعد این فرآیند یک struct جدید با id پیدا شده برای person ایجاد می کند و ویژگی های آن را هم دریافت و انتقال می دهد. سپس این را به mapping مربوط به people اضافه می کند. قرارداد هوشمند کامل شده به شکل زیر خواهد بود:

pragma solidity 0.5.1; contract MyContract { uint256 peopleCount = 0; mapping(uint => Person) public people; struct Person { uint _id; string _firstName; string _lastName; } function addPerson(string memory _firstName, string memory _lastName) public { peopleCount += 1; people[peopleCount] = Person(peopleCount, _firstName, _lastName); } }

عالی. یک مرور کلی روی مفاهیم اولیه انواع داده ها و ساختار داده ها در سالیدیتی داشتیم.

در بخش بعدی در مورد عملگرها، modifiers و زمان صحبت میکنیم. برای اطلاعات بیشتر در خصوص انواع ساختار داده ها خود کتابخانه سالیدیتی را بخوانید:

https://solidity.readthedocs.io/en/v0.4.24/types.html?highlight=data%20structure

قرارداد هوشمندسالیدیتیsolidityاتریومبیت کوین
یک مدیر پروژه فعال در حوزه بلاکچین
شاید از این پست‌ها خوشتان بیاید