آرایه‌‌ها (Arrays) در زبان سالیدیتی

بسیاری از مواقع قصد داریم گروهی از داده‌‌های مشابه را به یک تابع ارسال کنیم که از نظر تعداد شاید محدود باشند. اساسی‌‌ترین نوع داده برای این موقعیت، آرایه است (و در بسیاری مواقع می‌‌تواند برای اجرای ساختارهای پیشرفته‌‌تر مورد استفاده قرار بگیرد). در این مقاله با نحوه کار با انواع آرایه‌ها در زبان سالیدیتی آشنا خواهید شد.

0 105

شما می‌‌توانید مطابق تصویر زیر بدون هیچ مشکلی آرایه‌‌ها را رد و بدل کنید.

solidity

تصویر بالا از آرایه‌‌های یک واحد استفاده می‌‌کند که نشانگر یک عدد طبیعی 256 بیتی با اندازه نامحدود است. این یعنی من می‌‌توانم هر آرایه‌‌ی صحیحی را به تابع ارسال کنم. معنای دیگر آن این است که من باید آرایه برگشتی را در  getArrayMultipliedByScalar پیش از استفاده آن شروع کنم، چون در زمان اعلام آرایه خروجی، هیچ حافظه‌‌ای به عناصر خود اختصاص نمی‌‌دهد.

برای مقایسه، اگر من هر آرایه با اندازه ثابتی را استفاده کنم، دو اتفاق رخ خواهد داد:

  • دیگر نیازی به شروع آرایه خروجی ندارم.
  • اگر تابع آرایه‌‌ای با هر اندازه دیگری به جز 3 دریافت کند، کامپایلر خطایی را برمی‌‌گرداند.

solidity

می‌‌توانیم انواع دیگری از آرایه مانند bool و address را درست کنیم اما آرایه‌‌های چندبُعدی چه؟

می‌‌توانیم آرایه‌‌های دوبُعدی با اندازه ثابت را ارسال کنیم:

solidity

متاسفانه چیزها در آرایه‌‌های دینامیک (پویا) دشوارتر است.

برخی از زبان‌‌ها مثل BASIC و پاسکال، آرایه‌‌های دوبعدی را توسط دسته‌‌ای از شاخص‌‌های فهرست‌‌بندی می‌‌کنند. اما در زبان‌‌های مشتق از زبان C، آرایه‌‌هایی چندبعدی به جای ماتریکس، آرایه‌‌ی آرایه‌‌ها هستند. در سالیدیتی هم مسئله همین است و شناخت معنای این نوع اعلام مقداری زمان می‌‌برد: unit [2][4] با به عنوان (unit[2])[4] خوانده شود که به معنای 4 آرایه هر کدام با اندازه 2 است.

این وقتی اهمیت پیدا می‌‌کند که آرایه‌‌های دینامیک را در نظر می‌‌گیریم. می‌‌توانیم هر دوی این نوع‌‌ها را داشته باشیم:

solidity

اولین مثال بالا یک آرایه‌‌ی با اندازه ثابت است که سه عنصر دارد و هر عنصر یک آرایه دینامیک است. در مورد دوم، یک آرایه دینامیک …. داریم اما عناصر آن آرایه‌‌های با اندازه ثابت هستند.

من در پایین در مورد چگونگی شروع fixedSizeArray صحبت خواهم کرد که جالب‌‌ترینِ این دو مورد است. در مورد dynamicArray ، چون یک آرایه دینامیک است، اول باید حافظه‌‌ای را به آن اختصاص داد و سپس می‌‌توانیم به عناصر با اندازه ثابت دسترسی پیدا کنیم. مثال پایین می‌‌تواند کمک کند:

solidity

شروع آرایه‌‌های دینامیک چندبعدی

بیایید مثالی شبیه به مثال بالا را با جزییات بیشتری بررسی کنیم:

solidity

TypeEroor: حافظه Type unit256]3] مستقیما به فضای ذخیره Type unit256]3] قابل‌‌تبدیل نیست.

آرایه‌‌های fixedSizeArray  و dynamicArray  به عنوان متغیرهای وضعیت قرارداد اعلام می‌‌شوند، پس مرجع ذخیره هستند. با این حال می‌‌توانیم هر کدام از آرایه‌‌های درون fixedSizeArray  را با استفاده از عبارات آرایه حافظه، همانند بالا، شروع کنیم.

من برای مقایسه، دوم مورد دیگر را هم گنجانده‌‌ام که در آن‌‌ها سعی دارم می‌‌کنم یک آرایه حافظه را به یک آرایه ذخیره اختصاص بدهم. این در constructor کار می‌‌کند اما در تابع دوم نه. چرا؟

چون نوع‌‌های StorageArray و LoacaStorageArray دقیقا یکسان نیستند. نوع اول وضعیت متغیرهای یک قرار داد است و وقتی به داخل constructor ارجاع داده می‌‌شود نوع آن uint256[3] storage ref  است (برای تغییر این، مقدار صحیح تخصیصی را به یک چیز غیرقانونی مانند 7 تغییر دهید و پیام خطایی مشاهده خواهید کرد که نوع دخیل را هم نشان می‌‌دهد). در مقابل، نوع localStorageArray  از نوع uint256[3] storage pointer است. تفاوت کمی وجود دارد. در مورد اول به محل ذخیره ارجاع می‌‌دهیم و تخصیص آرایه‌‌ی حافظه را در آن فضای ذخیره کپی می‌‌کند. در مورد دوم سعی داریم چیزی را به یک متغیر محلی محول کنیم که طبق اسناد، تنها ارجاع جدیدی به pointer پیشین ایجاد می‌‌کرد:

تخصیص به متغیرهای ذخیره محلی تنها ارجاعی را محول می‌‌کنند و این ارجاع همیشه به متغفیر وضعیت اشاره دارد، حتی اگر مورد دوم در همین حال تغییر پیدا کند.

solidity

گزیده‌‌ای از مستندات سالیدیتی

در مثال بالا، y اشاره‌‌گر به مان موقعیتی است که به عنوان x شناخته می‌‌شود و تنظیم و تعدیل یکی باعث تغییر در دیگری می‌‌شود. اما در مورد ما، ما سعی داریم آرایه‌‌ی حافظه‌‌ای را به متغیر ذخیره‌‌ای محول کنیم که به دلیل تفاوت در نوع، نمی‌‌تواند pointerی به آن موقعیت حافظه ایجاد کند.

از سوی دیگر، وقتی fixedSizeArray را شروع می‌‌کنیم، در واقع به یک ارجاع ذخیره مراجعه می‌‌کنیم. در این مورد می‌‌توانیم از یک آرایه حافظه چیزی اختصاص بدهیم که منبع را بر هدف کاملا کپی و تمام محتوای پیشین آن را پاک می‌‌کند.

آیا می‌‌توانیم آرایه‌‌های چندبعدی را به توابع ارسال کنیم؟

بستگی دارد!

solidity

می‌‌توانیم از پلی‌‌مورفیسم یا چندریختی سالیدیتی برای نوشتن چهار تابع با یک نام و امضاهای متفاوت استفاده کنیم و همه‌‌ی ترکیبات آرایه‌‌های دینامیک و چندبعدی یک‌‌اندازه را کشف کنیم.

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

احتمالا این محدودیت با انتشار نسخه‌‌های جدید سالیدیتی از بین برود، اما در حال حاضر من از این ویژگی‌‌ها استفاده نمی‌‌کنم و به دنبال راه‌‌حل‌‌هایی می‌‌گردم.

ویژگی مشترک بین این دو نوع این است که نوع داخلی آرایه (یعنی نوع عناصر آن) دینامیک است و اندازه مشخصی ندارد. این نوع‌‌ها نمی‌‌توانند به یک تابع ارسال شده یا از آن برگردانده شوند.

این مطلب را با مثال دیگری نهایی خواهم کرد:

آخرین دو تابع غیرقانونی هستند. دلیل آن هم با همه چیزهایی که قبلا گفتیم همخوانی دارد: رشته‌‌ها و بایت‌‌ها از نوع دینامیک هستند. آنان آرایه هستند که کاراکترهای UTF-8 دارند و بایتی هستند. به همین دلیل، انواع بالا تنها آرایه‌‌های ساده چندبعدی مثل getIntها یا getAddressها نیستند، بلکه آرایه‌‌های دوبعدی با یک نوع دینامیک داخلی هستند. به همین دلیل نمی‌‌توانند در مرحله کنونی سالیدیتی به یک تابع ارسال شده یا از آن برگردانده شوند.

شاید از این مطالب هم خوشتان بیاید.

ارسال پاسخ

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