Rust: متغيرات Rust وأنواع البيانات

آخر تحديث: 2026-08-26

في لغة Rust، تكون المتغيرات غير قابلة للتغيير افتراضيًّا — وهذا ليس قيدًا، بل ضمانًا للأمان.

يُعد نظام المتغيرات والأنواع في لغة «Rust» حجر الزاوية في التزامها بسلامة الذاكرة. ويُعد فهم مبدأ الثبات، واستنتاج الأنواع، والأنواع القياسية الخطوة الأولى نحو إتقان لغة «Rust».


1. ما ستتعلمه



2. قصة حقيقية عن أمين صندوق

(1) التحدي: تصحيح الأخطاء في الأرقام في برنامج Excel

ليزا تعمل كصراف في متجر بقالة صغير. كل يوم بعد انتهاء العمل، تستخدم برنامج «إكسل» لحساب مبيعات اليوم:

بعد أن تعلمت لغة «Rust»، قالت: «لو كانت خلايا «Excel» غير قابلة للتعديل بشكل افتراضي، لما كان عليّ أن أقلق بشأن الكتابة فوق الصيغ».

(2) نموذج المتغيرات في لغة Rust

RUST
fn main() {
    let total_sales: f64 = 1280.50;   // Immutable by default -- Today's Sales
    // total_sales = 1500.00;         // ❌ Compilation Error: You cannot modify immutable variables!

    let mut daily_changes = 0.0;      // Use mut to declare a mutable variable
    daily_changes = 150.0;            // ✅ Can be modified
    daily_changes = daily_changes + 200.0;

    const TAX_RATE: f64 = 0.08;      // Compile-time constant, Global Fixed
    println!("Tax Rate: {}, Today's Accounts Receivable: {}", TAX_RATE, total_sales * (1.0 + TAX_RATE));
}

تتمثل فلسفة لغة «Rust» في: إذا كان من الممكن إبقاء الشيء على حاله، فلا تغيره. إن الثبات الافتراضي يجعل فهم الكود أسهل ويقلل من الأخطاء الناتجة عن التعديلات غير المقصودة.



3. إعلان المتغيرات

(1) let: غير قابل للتغيير افتراضيًا

RUST
let x = 5;       // Immutable Variable
// x = 10;       // ❌ Compilation Error: cannot assign twice to immutable variable

(2) let mut: المتغيرات القابلة للتغيير

RUST
let mut y = 5;   // Mutable Variable
y = 10;          // ✅ Can be reassigned

(3) const: ثابت وقت التحويل البرمجي

RUST
const MAX_POINTS: u32 = 100_000;   // The type must be specified.
const PI: f64 = 3.1415926535;
الخصائص let let mut const
التغير ثابت قابل للتغيير ثابت
موجود في وقت التشغيل نعم نعم لا (مُدمج في وقت التحويل البرمجي)
تعليق النوع اختياري اختياري إلزامي
النطاق العالمي لا لا نعم
تقييم التعبير وقت التشغيل وقت التشغيل ثابت وقت التحويل البرمجي


4. أنواع القيم العددية

تحتوي لغة Rust على أربعة أنواع أساسية من القيم العددية: الأعداد الصحيحة، والأعداد العائمة، والقيم المنطقية، والأحرف.

100%
graph TB
    A[Scalar Types] --> B[Integer: i8/u8/i16/u16/i32/u32/i64/u64/i128/u128]
    A --> C[Floating-point: f32/f64]
    A --> D[Boolean: bool]
    A --> E[Character: char]

(1) أنواع الأعداد الصحيحة

الطول موقّع غير موقّع النطاق
8 بت i8 u8 -128 ~ 127 / 0 ~ 255
16 بت i16 u16 -32768 ~ 32767 / 0 ~ 65535
32 بت i32 u32 ±2.1 مليار / 0 ~ 4.2 مليار
64 بت i64 u64 ±9.2 × 10¹⁸ / 0 ~ 1.8 × 10¹⁹
128 بت i128 u128 المدى الأقصى
arch isize usize يماثل عرض البت للنظام (نظام 64 بت = i64/u64)

النوع الصحيح الافتراضي هو i32 — فهو يوفر أفضل أداء ويفي بمعظم الاحتياجات.

(2) أنواع الأرقام العائمة

RUST
let a: f32 = 3.14;    // 32-bit precision floating-point (Single Precision)
let b: f64 = 3.141592653589793;  // 64-bit precision floating-point (Double Precision, Default Type)

النوع الافتراضي للأرقام العائمة هو f64 — في المعالجات الحديثة، تتساوى سرعة f64 وf32 تقريبًا، لكن f64 يوفر دقة أعلى.

(3) النوع المنطقي

RUST
let is_ok: bool = true;
let is_not = false;

تُستخدم القيم المنطقية عادةً في الجمل الشرطية، مثل التعبيرات الشرطية if وwhile.

(4) أنواع الشخصيات

RUST
let c: char = 'A';       // ASCII Character
let emoji: char = '🦀';  // Unicode Character(4 Byte)
let han: char = 'Rust';    // Unicode character

في لغة Rust، char هي قيمة عددية أحادية من Unicode تشغل 4 بايت. وهي ليست ASCII! وهذا يمنح لغة Rust دعمًا أصليًّا للتدويل.

النوع الحجم نطاق القيم الاستخدامات الشائعة
bool 1 بايت true / false عمليات الفحص الشرطية، العلامات
char 4 بايت قيمة عددية أحادية في يونيكود معالجة حرف واحد
f32 4 بايت ±3.4×10³⁸ (بدقة تبلغ 7 أرقام تقريبًا) الحوسبة الرسومية، وظائف التظليل في وحدة معالجة الرسومات (GPU)
f64 8 بايت ±1.8×10³⁰⁸ (دقة تبلغ 15 رقمًا تقريبًا) الحوسبة العلمية (النقطة العائمة الافتراضية)
i32 4 بايت ±2.1 مليار عدد صحيح للأغراض العامة (افتراضي)
u8 1 بايت 0–255 بيانات البايت، قيم RGB
usize arch يساوي عرض البت للنظام مؤشرات المصفوفات، حجم الحاوية


5. استدلال الأنواع والتعليقات التوضيحية

(1) ▶ المثال:استنتاج النوع (مستوى الصعوبة ⭐)

RUST
// ============================================
// Rust compiler infers types based on assignments
// ============================================

fn main() {
    let x = 42;           // Inferred as i32 (Default integer type)
    let y = 3.14;         // Inferred as f64 (Default floating-point type)
    let z = true;         // Inferred as bool
    let c = 'R';          // Inferred as char

    // Can use :type to view (Example in This Section, Not a standard method)
    println!("The value of x is: {}", x);
    println!("The value of y is: {}", y);
}

الناتج:

TEXT 📖 للعرض فقط
x The value is: 42
y The value is: 3.14

يقوم المُجمِّع باستنتاج الأنواع تلقائيًا بناءً على السياق، لذا لا يحتاج المطورون إلى تحديد تعليقات الأنواع في كل مكان.


(2) ▶ المثال:التعليق التوضيحي الصريح للنوع (مستوى الصعوبة ⭐)

RUST
// ============================================
// Explicitly Specify the Type -- When a specific size or precision is required
// ============================================

fn main() {
let small: u8 = 255;           // u8 Maximum value
let big: i64 = 9_223_372_036_854_775_807;  // An underscore can be used as a digit separator
let precise: f32 = 3.141592653589793;        // f32 May result in loss of precision
let flag: bool = 5 > 3;                      // The result of a Boolean expression

    println!("small: {}, big: {}, precise: {:.10}, flag: {}", small, big, precise, flag);
}

الناتج:

TEXT 📖 للعرض فقط
small: 255, big: 9223372036854775807, precise: 3.1415927410, flag: true

لاحظ أن f32 لا تتجاوز دقتها حوالي 7 أرقام معنوية، وأن 3.141592653589793 تم اقتطاعها لتصبح 3.1415927410.


(3) ▶ المثال:حجب المتغيرات (مستوى الصعوبة ⭐⭐)

RUST
// ============================================
// Shadowing: Overwrite a previous variable with the same name
// ============================================

fn main() {
    let x = 5;              // First x
    let x = x + 1;          // Shadowing: Second x, value becomes 6
    let x = x * 2;          // Shadowing: Third x, value becomes 12

    // Shadowing allows for a change in type!
    let name = "Rust";       // &str Type
    let name = name.len();   // became usize Type!

    println!("x value: {}", x);
    println!("name length: {}", name);
}

الناتج:

TEXT 📖 للعرض فقط
x value: 12
name length: 4

التظليل ≠ القابلية للتغيير. يؤدي التظليل إلى إنشاء متغير جديد (ذاكرة جديدة)، بينما mut يُعدّل نفس كتلة الذاكرة. يمكن للتظليل تغيير نوع المتغير ضمن نفس النطاق، لكن mut لا يستطيع ذلك.


(4) ▶ المثال:تمرين شامل — أداة إدارة المخزون (مستوى الصعوبة ⭐⭐⭐)

RUST
// ============================================
// Comprehensive Example: Using Variables, Shadowing and Constants in Inventory Management
// Demo let/mut/const/shadowing Practical Applications
// ============================================

const MAX_STOCK: u32 = 10_000;
const DISCOUNT_THRESHOLD: u32 = 500;

fn main() {
    let item_name = "Wireless Mouse";
    let price: f64 = 49.99;
    let mut stock: u32 = 2500;

    println!("=== Inventory Management System ===");
    println!("Products: {}", item_name);
    println!("Unit Price: {:.2} yuan", price);
    println!("Inventory: {} items", stock);

    stock = stock - 300;
    println!("\n--- Shipped Today 300 items ---");
    println!("Remaining Inventory: {} items", stock);

    let price = price * 0.85;
    println!("\n--- Member Discount 15% off ---");
    println!("Member Price: {:.2} yuan", price);

    let price = format!("{:.2} yuan", price);
    println!("Price Tag: {}", price);

    let total_value = (stock as f64) * 49.99;
    println!("\nTotal Inventory Value: {:.2} yuan", total_value);

    if stock > DISCOUNT_THRESHOLD {
        println!("Ample inventory (> {}), No need to restock", DISCOUNT_THRESHOLD);
    } else {
        let needed = MAX_STOCK - stock;
        println!("Out of Stock! Suggested Reorder {} items", needed);
    }

    println!("Maximum Capacity: {} items", MAX_STOCK);
}

الناتج:

TEXT 📖 للعرض فقط
=== Inventory Management System ===
Products: Wireless Mouse
Unit Price: 49.99 yuan
Inventory: 2500 items

--- Shipped Today 300 items ---
Remaining Inventory: 2200 items

--- Member Discount 15% off ---
Member Price: 42.49 yuan
Price Tag: 42.49 yuan

Total Inventory Value: 109978.00 yuan
Ample inventory (> 500), No need to restock
Maximum Capacity: 10000 items

يجمع هذا المثال بين استخدام الثابت const، والمتغير غير القابل للتغيير let، والمتغير القابل للتغيير let mut، وتظليل المتغيرات (حيث يتغير النوع المُظلَّل من f64 إلى String)، مما يوضح كيفية تضافر طرق إعلان المتغيرات المختلفة هذه معًا في سيناريو واقعي.


(5) ▶ المثال:تجاوز سعة الأعداد الصحيحة والحساب الآمن (مستوى الصعوبة ⭐⭐)

RUST
// ============================================
// Integer Overflow Behavior: debug mode panic vs release mode wrapping
// ============================================

fn main() {
    let max_u8: u8 = 255;
    println!("u8 Maximum value: {}", max_u8);

    // Safe Computation Method (No panic, Returns overflow result)
    let (result, did_overflow) = max_u8.overflowing_add(1);
    println!("255 + 1 (overflowing_add): {}, Did overflow?: {}", result, did_overflow);

    let checked = max_u8.checked_add(1);
    println!("255 + 1 (checked_add): {:?}", checked);

    let saturating = max_u8.saturating_add(100);
    println!("255 + 100 (saturating_add): {}", saturating);

    let wrapping: u8 = max_u8.wrapping_add(1);
    println!("255 + 1 (wrapping_add): {}", wrapping);

    let neg_i8: i8 = -128;
    let (abs_result, overflow) = neg_i8.overflowing_abs();
    println!("i8 absolute value of minimum: {}, Did overflow?: {}", abs_result, overflow);
}

الناتج:

TEXT 📖 للعرض فقط
u8 Maximum value: 255
255 + 1 (overflowing_add): 0, Did overflow?: true
255 + 1 (checked_add): None
255 + 100 (saturating_add): 255
255 + 1 (wrapping_add): 0
i8 absolute value of minimum: -128, Did overflow?: true

في لغة Rust، يؤدي تجاوز سعة الأعداد الصحيحة إلى حدوث حالة «panic» في وضع التصحيح، ولكنه يؤدي إلى «التفاف» في وضع الإصدار. يُنصح باستخدام الطرق checked_* وsaturating_* وwrapping_* للتحكم بشكل صريح في سلوك التجاوز.


(6) ▶ المثال:التطبيق العملي لتظليل المتغيرات وتحويل الأنواع (مستوى الصعوبة: ⭐⭐⭐)

RUST
// ============================================
// Practical Examples of Variable Shadowing: String Parsing Chain
// ============================================

fn main() {
    let input = "42.5";
    println!("Original Input: {} (Type: &str)", input);

    let input = input.parse::<f64>();
    println!("Analysis Results: {:?}", input);

    let input = match input {
        Ok(value) => value,
        Err(_) => 0.0,
    };
    println!("After unpacking: {} (Type: f64)", input);

    let input = input as i32;
    println!("Round to an integer: {} (Type: i32, Truncation of Decimals)", input);

    let input = input * 2;
    println!("After doubling: {} (Type: i32)", input);

    let input = format!("Result: {}", input);
    println!("Final Output: {} (Type: String)", input);

    let alice_score = "95";
    let alice_score = alice_score.parse::<u32>().unwrap_or(0);
    let alice_grade = if alice_score >= 90 { "A" } else { "B" };
    println!("Alice: Score={}, Level={}", alice_score, alice_grade);
}

الناتج:

TEXT 📖 للعرض فقط
Original Input: 42.5 (Type: &str)
Analysis Results: Ok(42.5)
After unpacking: 42.5 (Type: f64)
Round to an integer: 42 (Type: i32, Truncation of Decimals)
After doubling: 84 (Type: i32)
Final Output: Result: 84 (Type: String)
Alice: Score=95, Level=A

يتيح «تظليل المتغيرات» التحويل التدريجي لأنواع البيانات ضمن نفس النطاق — من &strResult<f64>f64i32String — باستخدام نفس اسم المتغير في كل خطوة، مما ينتج عنه كود واضح وخالٍ من التكرار.



❓ أسئلة شائعة

س ما الفرق بين i32 و u32؟
ج القيم التي تبدأ بحرف "i" هي قيم موقعة (يمكن أن تكون موجبة أو سالبة)، بينما القيم التي تبدأ بحرف "u" هي قيم غير موقعة (لا يمكن أن تكون إلا غير سالبة).
س لماذا يكون الإعداد الافتراضي في Rust هو i32 بدلاً من i64؟
ج بسبب المفاضلة بين الأداء والكفاءة.
س ما الفرق بين التظليل وlet mut؟
ج التظليل ينشئ متغيرًا جديدًا (من نوع مختلف)، بينما mut يُعدِّل المتغير نفسه (دون تغيير نوعه).
س بما أن char يشغل 4 بايت، ألا تُعد السلاسل مضيعة للمساحة؟
ج سلاسل Rust ليست مصفوفات من char.
س ما الفرق بين const وlet؟
ج يتم دمج const في النص في وقت التحويل البرمجي، بينما يتم تخصيص let في وقت التشغيل.

📖 ملخص


📝 تمارين

  1. الصعوبة ⭐: قم بتعريف متغير من النوع u16 وقم بتعيين القيمة 65535 له، ثم حاول تغييرها إلى 65536 ولاحظ رسالة الخطأ التي يعرضها المُترجم.
  2. الصعوبة ⭐⭐: اكتب برنامجًا يستخدم let mut لإعلان متغير يحسب مجموع الأعداد من 1 إلى 5، ثم يعرض النتيجة.
  3. الصعوبة ⭐⭐⭐: حاول تعريف الثابت const خارج الدالة fn main() واستخدامه داخل الدالة. ثم حاول تعريف المتغير let خارج الدالة ولاحظ خطأ المُترجم — سيساعدك ذلك على فهم النطاق العام لـ const.
Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%