الحقول الخاصة
جزء من قسم البرمجة كائنية التوجه في رحلة Rust على Coddy. الدرس 10 من 61.
في الدرس السابق، جعلت كل شيء public: الـ struct، وfield الخاصة به، وطرقه. لكن التغليف الحقيقي يعني التحكم في كيفية access بياناتك. في Rust، يمكنك جعل struct عامًا مع إبقاء field الخاصة به private.
تخيّل Wallet الذي يجب ألّا يكون له balance سالبًا على الإطلاق. إذا كان field public، فبإمكان أي شخص تعيين أي قيمة له:
// wallet.rs
pub struct Wallet {
balance: f64, // بدون pub = خاص!
}
impl Wallet {
pub fn new(initial: f64) -> Wallet {
Wallet { balance: initial }
}
}
لاحظ أن Wallet عام، لكن balance لا يحتوي على الكلمة المفتاحية pub. هذا يعني أن الشيفرة الموجودة خارج الوحدة يمكنها إنشاء Wallet باستخدام constructor، لكنها لا تستطيع قراءة حقل balance أو تعديله مباشرةً:
// main.rs
mod wallet;
use wallet::Wallet;
fn main() {
let w = Wallet::new(100.0);
// println!("{}", w.balance); // خطأ! الحقل خاص
// w.balance = -50.0; // خطأ! لا يمكن الوصول إلى الحقل الخاص
}
هذا هو أساس التغليف: يتحكم struct في بياناته الخاصة. يجب على التعليمات البرمجية الخارجية المرور عبر الأساليب التي توفرها، ما يعني أنه يمكنك إضافة التحقق أو التسجيل أو أي منطق آخر. تظل البيانات محمية من الحالات غير الصالحة.
في الدروس القادمة، ستتعلّم كيفية توفير access مُتحكَّم به إلى هذه البيانات private من خلال أساليب getter وsetter.
التحدي
سهللنبنِ نظام sensor لدرجة الحرارة يوضّح التغليف من خلال إبقاء البيانات الحساسة محمية داخل وحدة.
ستنشئ ملفين لتنظيم التعليمات البرمجية:
sensor.rs: عرّفTemperatureSensorstructمع fieldين:location(String) وreading(f64). يجب أن تكون البنية public حتى يمكن استخدامها من ملفات أخرى، لكن أبقِ كلا fieldين private: يجب ألا تتمكن التعليمات البرمجية الخارجية من access بيانات sensor أو تعديلها مباشرةً. أضف constructor newpublic يأخذ اسم location وقراءة درجة حرارة initial.main.rs: أدرِج وحدة sensor وأنشئTemperatureSensorusing constructor. بما أن fieldين private، لن تتمكن من طباعتهما مباشرةً؛ وبدلاً من ذلك، اطبع confirmation message تُظهر أن sensor تم created بنجاح.
يركّز هذا التحدي على المفهوم الأساسي للحقول private: إن struct متاح، لكن بياناته الداخلية محمية. لا يمكن للتعليمات البرمجية الخارجية التفاعل مع sensor إلا من خلال الأساليب التي توفرها (في هذه الحالة، constructor فقط).
يجب أن يتبع ناتجك هذا التنسيق exact:
Sensor created for: {location}للوصول إلى location بغرض طباعته، ستحتاج إلى جعل دالة new تطبع هذه الرسالة قبل إرجاع sensor، لأن field نفسه private.
على سبيل المثال، إذا أنشأت sensor باستخدام location "Kitchen" وreading 22.5، فسيكون الناتج:
Sensor created for: Kitchenستتلقى مدخلين: اسم location وreading درجة الحرارة initial.
جرّب بنفسك
mod sensor;
use sensor::TemperatureSensor;
fn main() {
// اقرأ الإدخال
let mut location = String::new();
std::io::stdin().read_line(&mut location).expect("Failed to read line");
let location = location.trim().to_string();
let mut reading_str = String::new();
std::io::stdin().read_line(&mut reading_str).expect("Failed to read line");
let reading: f64 = reading_str.trim().parse().expect("Failed to parse reading");
// TODO: أنشئ TemperatureSensor باستخدام المُنشئ
// ستتولى الدالة new طباعة رسالة التأكيد
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1الأساليب والسلوك
مقدمة في كتل التنفيذمعامل Selfالأساليب القابلة للتعديلالدوال المرتبطةكتل تنفيذ متعددةتسلسل الأساليبمراجعة - إجراءات المستطيل4مشروع: حيوان أليف افتراضي
تعريف الحيوان الأليفإطعام الحيوان الأليف2التغليف والوحدات البرمجية
أساسيات الوحدات البرمجيةالكلمة المفتاحية Publicالحقول الخاصةدوال Gettersدوال Settersمراجعة - الخزانة الآمنة5الأنواع العامة (Generics)
الـ Structs العامةالـ Methods العامةأنواع عامة متعددةالـ Functions العامةمراجعة - Coordinate Point3التعدادات المتقدمة (Advanced Enums)
التعدادات مع البياناتالأساليب (Methods) في التعداداتمطابقة حالات البياناتمراجعة التعداد Optionملخص - التعداد Shape6تعريف الـ Traits
ما هي الـ Trait؟تنفيذ الـ Traitsالتنفيذات الافتراضيةتجاوز التنفيذات الافتراضيةالـ Traits مع المعاملاتملخص - مشغل الوسائطتدرّب بنفسك: مترجم Rust عبر الإنترنت