دوال Setters
جزء من قسم Object Oriented Programming في رحلة Rust على Coddy — الدرس 12 من 61.
تسمح دوال الجلب (Getters) للكود الخارجي بـ قراءة البيانات الخاصة. ولكن ماذا لو كنت بحاجة للسماح له بـ تغييرها؟ هنا يأتي دور دوال التعيين (setter methods)—وهي دوال عامة تقوم بتعديل الحقول الخاصة بطريقة محكومة.
يأخذ المُعيّن (setter) الأساسي &mut self وقيمة جديدة:
// wallet.rs
pub struct Wallet {
balance: f64,
}
impl Wallet {
pub fn new(initial: f64) -> Wallet {
Self { balance: initial }
}
pub fn balance(&self) -> f64 {
self.balance
}
pub fn set_balance(&mut self, amount: f64) {
self.balance = amount;
}
}
على عكس الـ getters، تستخدم الـ setters في Rust عادةً البادئة set_ للإشارة بوضوح إلى أنها تقوم بتعديل البيانات. يُعد المعامل &mut self ضرورياً—فهو يمنح الدالة (method) الإذن لتغيير حقول الـ struct.
القوة الحقيقية للمُعيّنات (setters) هي التحقق من الصحة. فبدلاً من قبول أي قيمة بشكل أعمى، يمكنك فرض القواعد:
pub fn set_balance(&mut self, amount: f64) {
if amount >= 0.0 {
self.balance = amount;
}
// يتم تجاهل القيم السالبة بصمت
}
الآن تحمي المحفظة نفسها—بغض النظر عن القيمة التي يحاول الكود الخارجي تعيينها، لا يمكن أن يصبح الرصيد سالباً أبداً. هذا هو التغليف (encapsulation) في أبهى صوره: يتحكم الـ struct في ثوابته الخاصة، ولا يمكن للكود الخارجي ببساطة وضعه في حالة غير صالحة.
التحدي
سهللنقم ببناء نظام ترموستات يوضح كيف يمكن للمعدلات (setters) فرض قواعد للحفاظ على صحة البيانات. سيكون للترموستات الخاص بك إعداد درجة حرارة لا يمكن تعديله إلا ضمن نطاق آمن.
ستقوم بإنشاء ملفين لتنظيم الكود الخاص بك:
thermostat.rs: قم بتعريف هيكلThermostatمع حقلtemperatureخاص (i32). يجب أن يكون الهيكل عاماً (public)، لكن الحقل يبقى خاصاً لحمايته من القيم غير الصالحة. قم بتنفيذ ما يلي:- منشئ
newيأخذ درجة حرارة أولية - دالة جلب
temperature(getter) تعيد درجة الحرارة الحالية - دالة تعديل
set_temperature(setter) تقبل فقط القيم بين 10 و 30 (شاملة). إذا كانت القيمة خارج هذا النطاق، يجب أن تظل درجة الحرارة دون تغيير.
- منشئ
main.rs: قم باستيراد وحدة الترموستات الخاصة بك، وأنشئ ترموستات، ووضح التحقق من صحة المعدل (setter) من خلال محاولة ضبط درجات حرارة مختلفة وطباعة النتيجة بعد كل محاولة.
يجب أن يتجاهل المعدل (setter) القيم غير الصالحة بصمت — لا توجد رسائل خطأ، فقط احتفظ بدرجة الحرارة الحالية دون تغيير عندما يحاول شخص ما ضبطها خارج النطاق الصالح.
يجب أن يتبع مخرجك هذا التنسيق تماماً:
Initial: {temperature}
After setting to {attempted_value}: {temperature}
After setting to {attempted_value}: {temperature}على سبيل المثال، إذا قمت بإنشاء ترموستات عند 20، ثم حاولت ضبطه على 25 (صالح) ثم 50 (غير صالح)، فسيكون المخرج:
Initial: 20
After setting to 25: 25
After setting to 50: 25ستتلقى ثلاثة مدخلات: درجة الحرارة الأولية، ودرجة الحرارة الأولى للمحاولة، ودرجة الحرارة الثانية للمحاولة.
ورقة مرجعية
تسمح دوال التعيين (Setter methods) للكود الخارجي بتعديل الحقول الخاصة بطريقة محكومة. وهي تأخذ &mut self للحصول على إذن لتغيير بيانات الـ struct.
الصيغة الأساسية لدالة التعيين:
pub fn set_balance(&mut self, amount: f64) {
self.balance = amount;
}عادةً ما تستخدم دوال التعيين في Rust البادئة set_ للإشارة بوضوح إلى أنها تقوم بتعديل البيانات.
تُمكّن دوال التعيين من التحقق من الصحة لفرض القواعد والحفاظ على سلامة البيانات:
pub fn set_balance(&mut self, amount: f64) {
if amount >= 0.0 {
self.balance = amount;
}
// يتم تجاهل القيم غير الصالحة بصمت
}هذا هو التغليف (encapsulation) في أبهى صوره: حيث يتحكم الـ struct في ثوابته الخاصة، مما يمنع الكود الخارجي من وضعه في حالة غير صالحة.
جرّب بنفسك
mod thermostat;
use thermostat::Thermostat;
fn main() {
// قراءة المدخلات
let mut input1 = String::new();
std::io::stdin().read_line(&mut input1).expect("Failed to read line");
let initial_temp: i32 = input1.trim().parse().expect("Invalid number");
let mut input2 = String::new();
std::io::stdin().read_line(&mut input2).expect("Failed to read line");
let first_attempt: i32 = input2.trim().parse().expect("Invalid number");
let mut input3 = String::new();
std::io::stdin().read_line(&mut input3).expect("Failed to read line");
let second_attempt: i32 = input3.trim().parse().expect("Invalid number");
// TODO: إنشاء منظم حرارة (thermostat) بدرجة الحرارة الأولية
// TODO: طباعة درجة الحرارة الأولية
// التنسيق: "Initial: {temperature}"
// TODO: محاولة ضبط درجة الحرارة الأولى وطباعة النتيجة
// التنسيق: "After setting to {attempted_value}: {temperature}"
// TODO: محاولة ضبط درجة الحرارة الثانية وطباعة النتيجة
// التنسيق: "After setting to {attempted_value}: {temperature}"
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1الأساليب والسلوك
مقدمة في كتل التنفيذمعامل Selfالأساليب القابلة للتعديلالدوال المرتبطةكتل تنفيذ متعددةتسلسل الأساليبمراجعة - إجراءات المستطيل4مشروع: حيوان أليف افتراضي
تعريف الحيوان الأليفإطعام الحيوان الأليف2التغليف والوحدات البرمجية
أساسيات الوحدات البرمجيةالكلمة المفتاحية Publicالحقول الخاصةدوال Gettersدوال Settersمراجعة - الخزانة الآمنة5الأنواع العامة (Generics)
الـ Structs العامةالـ Methods العامةأنواع عامة متعددةالـ Functions العامةمراجعة - Coordinate Point3التعدادات المتقدمة (Advanced Enums)
التعدادات مع البياناتالأساليب (Methods) في التعداداتمطابقة حالات البياناتمراجعة التعداد Optionملخص - التعداد Shape6تعريف الـ Traits
ما هي الـ Trait؟تنفيذ الـ Traitsالتنفيذات الافتراضيةتجاوز التنفيذات الافتراضيةالـ Traits مع المعاملاتملخص - مشغل الوسائط