استخدام التوابع (Methods) ضمن الهياكل (Structs) في لغة رست (Rust)
تُعتبر لغة رست (Rust) من اللغات النظامية الحديثة التي تركز على الأمان، الأداء، والتحكم الدقيق في إدارة الذاكرة بدون الحاجة إلى جامع نفايات (Garbage Collector). من أهم مفاهيم البرمجة التي تدعمها اللغة هي البرمجة الكائنية التوجه (Object-Oriented Programming) ولكن بطريقة فريدة تختلف عن اللغات التقليدية مثل C++ أو Java. من بين هذه المفاهيم المهمة نجد التوابع (Methods) المرتبطة بالهياكل (Structs) والتي تلعب دوراً مركزياً في تصميم البرمجيات بلغة رست.
تعريف الهياكل في رست
الهياكل في رست تُستخدم لتعريف نوع بيانات مركب يحتوي على مجموعة من القيم المرتبطة. تُشبه إلى حد كبير الكائنات (Objects) في اللغات الكائنية التوجه. يتم تعريف الهيكل باستخدام الكلمة المفتاحية struct، وتُحدد الحقول داخله بطريقة واضحة ودقيقة مع تحديد نوع كل حقل.
ruststruct Rectangle {
width: u32,
height: u32,
}
الهياكل كما هي لا تحتوي على سلوك (أي لا تحتوي على توابع) بل مجرد بيانات. لإعطاء الهيكل سلوكاً (أي توابع يمكن استدعاؤها عليه)، يتم استخدام ما يُعرف بالكتلة impl.
الكتلة impl في رست
الكتلة impl، وهي اختصار لكلمة implementation، تُستخدم لتعريف التوابع المرتبطة بنوع معين من الهياكل. هذه التوابع يمكن أن تُعتبر كبدائل للوظائف أو الدوال الأعضاء في لغات أخرى، وهي تعزز من مبدأ التجميع بين البيانات والسلوك.
تعريف تابع داخل impl
لنفترض أننا نريد أن نحسب المساحة لمستطيل مُعرف كهيكل Rectangle. يمكننا تعريف تابع داخل كتلة impl على النحو التالي:
rustimpl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
شرح الكود
-
impl Rectangle: نحدد أن الكتلة التالية خاصة بتنفيذ التوابع لهيكلRectangle. -
fn area(&self) -> u32: تابع يُعيد مساحة المستطيل. -
&self: تشير إلى مرجع غير قابل للتغيير للهيكل الحالي. وهو ما يعادلthisفي لغات أخرى.
استخدام التابع
rustfn main() {
let rect = Rectangle {
width: 30,
height: 50,
};
println!("The area is {}.", rect.area());
}
الفرق بين أنواع المراجع في التوابع
رست تميز بين ثلاثة أنواع رئيسية من المراجع المستخدمة في تعريف التوابع داخل impl:
| نوع المرجع | الوصف | المثال |
|---|---|---|
&self |
مرجع غير قابل للتغيير | قراءة بيانات دون تعديل |
&mut self |
مرجع قابل للتغيير | تعديل بيانات الهيكل داخلياً |
self |
أخذ الملكية | استهلاك الكائن |
تابع يُعدل الحقول باستخدام &mut self
rustimpl Rectangle {
fn double_width(&mut self) {
self.width *= 2;
}
}
تابع يستهلك الكائن باستخدام self
rustimpl Rectangle {
fn destroy(self) {
println!("Rectangle with width {} is destroyed.", self.width);
}
}
عند استخدام self في التابع، فإننا ننقل الملكية، وبالتالي لا يمكن استخدام الكائن بعد استدعاء هذا التابع.
التوابع المرتبطة Associated Functions
إلى جانب التوابع التي تعمل على كائن معين، توفر رست أيضاً ما يُعرف بـ “التوابع المرتبطة” والتي لا تأخذ self كمعامل. وهي غالباً تُستخدم كمُنشئات (Constructors) أو توابع مساعدة.
rustimpl Rectangle {
fn new(width: u32, height: u32) -> Self {
Self { width, height }
}
}
يمكن استخدام هذا التابع بالشكل التالي:
rustlet rect = Rectangle::new(10, 20);
أكثر من كتلة impl
من الممكن تعريف عدة كتل impl لنفس الهيكل، مما يُوفر إمكانية تنظيم التوابع حسب المهام أو الوظائف.
rustimpl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
impl Rectangle {
fn perimeter(&self) -> u32 {
2 * (self.width + self.height)
}
}
استدعاء التوابع كسلسلة
بفضل مرجعية &mut self أو self، يمكن تصميم التوابع بحيث تُعيد Self مما يسمح باستدعائها كسلسلة توابع (Method Chaining):
rustimpl Rectangle {
fn increase_width(mut self, value: u32) -> Self {
self.width += value;
self
}
fn increase_height(mut self, value: u32) -> Self {
self.height += value;
self
}
}
الاستدعاء:
rustlet rect = Rectangle { width: 10, height: 20 }
.increase_width(5)
.increase_height(10);
استخدام Traits لتوسيع الهياكل
التوابع يمكن أيضًا أن تُعرف من خلال traits، وهي واجهات تُستخدم لتحديد وظائف مشتركة بين أنواع متعددة. يمكن استخدامها لتعريف توابع عامة تُطبق على أنواع متعددة.
rusttrait Shape {
fn area(&self) -> u32;
}
impl Shape for Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
تنظيم الكود باستخدام Modules
عند استخدام الهياكل والتوابع في مشاريع متقدمة، يُنصح بتقسيم الكود إلى وحدات (Modules) وفصل تعريف الهيكل عن التوابع. يمكن وضع الهيكل في ملف، والتوابع في ملف آخر، وتجميعها باستخدام mod وpub.
مقارنة مع لغات أخرى
رست لا تستخدم الوراثة التقليدية كما في Java أو C++، بل تعتمد على التجميع (Composition) والسمات (Traits) لتحقيق السلوك. هذا النهج يُشجع على كتابة شيفرات أكثر أمانًا وقابلية لإعادة الاستخدام.
جدول مقارنة مختصر:
| المفهوم | Rust | C++ | Java |
|---|---|---|---|
| التوابع | داخل impl |
داخل الصنف | داخل الصنف |
| وراثة | غير موجودة، يستخدم Traits | نعم | نعم |
self |
مرجع صريح &self أو &mut self أو self |
ضمني | ضمني (this) |
متى نستخدم التوابع في رست؟
-
عندما تحتاج إلى سلوك مخصص متعلق بالبيانات داخل هيكل معين.
-
عندما ترغب في تغليف البيانات وإخفاء التفاصيل الداخلية.
-
لتوفير واجهات استخدام مريحة وواضحة من خلال منشئات أو توابع معالجة.
-
عند استخدام مفاهيم مثل النماذج العامة (Generics) و السمات (Traits) لتوسيع الهيكل دون تعديل مباشر فيه.
دعم التعددية الشكلية (Polymorphism)
من خلال استخدام السمات (Traits) يمكن توفير آلية لتعددية الأشكال عبر الواجهات، ما يسمح باستدعاء توابع معينة على أنواع متعددة بشرط تنفيذها لنفس السمة.
rustfn print_area(shape: T) {
println!("Area: {}", shape.area());
}
فوائد استخدام التوابع ضمن impl
-
فصل السلوك عن البيانات عند الحاجة.
-
تنظيم الكود وتحسين القراءة.
-
تقليل الاعتماد على الوظائف الخارجية.
-
تمكين الاستخدام الآمن للذاكرة والملكية بفضل نظام المراجع الفريد لرست.
الخلاصة
التوابع (Methods) داخل الهياكل (Structs) في رست تمثل جزءاً أساسياً من فلسفة التصميم الخاصة باللغة والتي تجمع بين الأداء العالي والأمان. من خلال الكتلة impl يمكن إضافة وظائف وسلوكيات لأنواع البيانات المعرفة، مع ضمان تحكم دقيق في المراجع والملكية. بفضل الدعم القوي للسمات (Traits)، يمكن تصميم أنظمة معقدة دون الحاجة إلى وراثة تقليدية، مما يجعل رست خياراً قوياً لتطوير تطبيقات آمنة وفعالة.
المراجع
-
The Rust Programming Language. Steve Klabnik and Carol Nichols. https://doc.rust-lang.org/book/
-
Rust by Example. https://doc.rust-lang.org/rust-by-example/

