پرش به مطلب اصلی

ساختار

خلاصه

ساختارهای زبان Wave جزء عناصر اصلی دستور زبان برای اعلام نوع‌های دادهٔ تعریف‌شده توسط کاربر هستند. با استفاده از ساختارها، می‌توان مقادیر از نوع‌های مختلف را به یک واحد منطقی تبدیل کرد و به این ترتیب، می‌توان ساختار داده‌های پیچیده را به‌طور دقیق و ایمن مدلسازی کرد.

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

دستور زبان اعلام ساختار

ساختار با استفاده از کلیدواژه struct اعلام می‌شود. نام ساختار از نگارش پاسکال (PascalCase) استفاده می‌کند و می‌توان یک یا چند فیلد در بدنهٔ ساختار تعریف کرد.

فیلدها به صورت نام: نوع; اعلان می‌شوند و بعد از هر اعلان فیلد، وجود نقطه ویرگول لازم است.

struct Box {
size: i32;
weight: f32;
}

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

دستور زبان ایجاد ساختار

ساختار با استفاده از نام ساختار به صورت نوع لیترال ساخته می‌شود. لفظ های ساختاری به شکل StructName { field_name: value; ... } نوشته می شوند.

var b: Box = Box {
size: 42;
weight: 10.5;
};

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

در زمان مقداردهی اولیه، نیازی نیست که ترتیب نوشتن فیلدها با ترتیب اعلام آنها در ساختار مطابقت داشته باشد، اما نوع مقدار داده شده به هر فیلد باید دقیقاً با نوع تعریف شده در ساختار مطابقت داشته باشد. در Wave، در طول فرآیند مقداردهی اولیه فیلدهای ساختار، تبدیل نوع ضمنی مجاز نیست.


دستور زبان دسترسی به فیلد ساختار

فیلدهای ساختار از طریق نگارش نقطه‌ای در دسترس هستند. دسترسی به فیلد از دستور زبان یکسانی برای خواندن و نوشتن استفاده می‌کند.

println("Size: {}", b.size);
println("Weight: {}", b.weight);

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


دستور زبان تعریف متد ساختار

زبان Wave مستقیماً متدها را در درون ساختارها تعریف نمی‌کند. به جای آن، از کلیدواژه proto برای اعلام مجموعه‌ای از متدهای مرتبط با یک ساختار استفاده می‌کند.

بلوک proto بخشی از توابع مرتبط با یک ساختار خاص است، و توابعی که در این بلوک تعریف شده‌اند به‌عنوان متدهای آن ساختار به‌کار می‌روند.

متدها از self به‌عنوان اولین پارامتر برای دریافت نمونه‌ای از ساختار استفاده می‌کنند. self به معنای ارزش کل ساختار است و به‌صورت انتقال مقداری کپی می‌شود.

proto Box {
fun print(self) {
println("size={}, weight={}", self.size, self.weight);
}

fun added_size(self, x: i32) -> i32 {
return self.size + x;
}
}

بلوک proto لزوماً نیاز ندارد که در همان فایل با اعلام ساختار قرار گیرد، و از طریق چندین بلوک proto می‌توان متدها را برای یک ساختار مشابه به صورت پراکنده تعریف کرد.

فراخوانی متدها از نماد نقطه استفاده می‌کند و به همان شیوه‌ای عمل می‌کند که فراخوانی توابع عمومی صورت می‌گیرد.

b.print();
var n: i32 = b.added_size(5);

استفاده از ساختار به عنوان آرگومان تابع

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

fun calc(box: Box) -> i32 {
return box.size * 2;
}

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


ساختار تو در تو (Nested Struct)

در زبان Wave می‌توان از دیگر ساختارها به عنوان نوع فیلد یک ساختار استفاده کرد. ساختار به عنوان یک نوع کامل اجازه می‌دهد که درون آن ساختارهای دیگری را به‌صورت تو در تو آزادانه وارد کنید.

struct Position {
x: i32;
y: i32;
}

struct Player {
name: str;
pos: Position;
}

به فیلدهای ساختارهای تو در تو با استفاده‌ی پیوسته از نماد نقطه دسترسی می‌یابیم.

var p: Player = Player {
name: "Alice";
pos: Position { x: 10; y: 20; };
};

println("Player X: {}", p.pos.x);
println("Player Y: {}", p.pos.y);

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


آرایه ساختار

می‌توان از ساختار به عنوان نوع عنصرهای یک آرایه استفاده کرد. دستور زبان آرایه در Wave از فرمت array<نوع، طول> استفاده می‌کند و می‌توان نوع ساختار را نیز به همان صورت تعیین کرد.

var players: array<Player, 3> = [
Player { name: "A"; pos: Position { x: 1; y: 2; }; },
Player { name: "B"; pos: Position { x: 3; y: 4; }; },
Player { name: "C"; pos: Position { x: 5; y: 6; }; }
];

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

println("Second Player X: {}", players[1].pos.x);

بررسی امکان عملیات پایه‌ای بر روی ساختارها

ساختارهای Wave به دلیل اینکه نوع‌های تعریف‌شده کاربر هستند، به‌طور خودکار در عملیات‌های حسابی یا مقایسه‌ای شرکت نمی‌کنند.

اگر مقایسه تساوی، مرتب‌سازی، ایجاد هش، و عملیات عددی ساختارها ضروری است، باید حتماً از طریق بلاک proto این عملیات‌ها را به‌طور واضح تعریف کنید. Wave برای ساختارها عملگرهای ضمنی ارائه نمی‌دهد، و اصولاً همه تعاملات باید به‌طور آشکار تعریف شوند.