0Pricing
Learn Rust Coding · درس

Fn وFnMut وFnOnce

سمات الإغلاق

Fn وFnMut وFnOnce درس مجاني في Learn Rust Coding على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Learn Rust Coding، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Learn Rust Coding 4 دروس في المجموع.

سمات Closure

تنفذ كل Closure تلقائيًا سمة واحدة أو أكثر من ثلاث سمات، بناءً على طريقة استخدامها للقيم الملتقطة:

  • Fn — تستعير بشكل غير قابل للتغيير.
  • FnMut — تستعير بشكل قابل للتغيير.
  • FnOnce — تتولى الملكية ويمكن استدعاؤها مرة واحدة.
fn main() {
    let x = 5;
    let show = || println!("x is {}", x); // implements Fn
    show();
    show();
}

Fn: استعارة غير قابلة للتغيير

تنفذ Closure التي تقرأ القيم الملتقطة فقط السمة Fn. ويمكن استدعاؤها مرات عديدة من دون تغيير أي شيء.

fn main() {
    let greeting = String::from("Hi");
    let say = || println!("{}", greeting);
    say();
    say();
}

FnMut: استعارة قابلة للتغيير

تنفذ Closure التي تغيّر قيمة ملتقطة السمة FnMut. ويجب أن يكون متغير Closure نفسه mut لاستدعائها.

fn main() {
    let mut count = 0;
    let mut increment = || {
        count += 1;
        println!("count {}", count);
    };
    increment();
    increment();
}

FnOnce: تتولى الملكية

تنفذ Closure التي تنقل قيمة ملتقطة خارج البيئة السمة FnOnce. ولا يمكن استدعاؤها إلا مرة واحدة.

fn main() {
    let name = String::from("Ada");
    let consume = move || {
        let owned = name;
        println!("consumed {}", owned);
    };
    consume();
}

تسلسل السمات الهرمي

تشكل السمات تسلسلًا هرميًا:

  • كل Fn هي أيضًا FnMut وFnOnce.
  • كل FnMut هي أيضًا FnOnce.

لذلك تُعد Fn الأكثر مرونة، بينما تُعد FnOnce الأقل مرونة.

fn main() {
    let value = 42;
    let read = || value; // Fn, so also FnMut and FnOnce
    println!("{}", read());
}

تمرير Fn إلى الدوال

يمكن للدالة قبول Closure بتحديد السمة التي تحتاج إليها. استخدموا الأنواع العامة مع قيد سمة.

fn apply<F: Fn(i32) -> i32>(f: F, x: i32) -> i32 {
    f(x)
}

fn main() {
    let double = |n| n * 2;
    println!("{}", apply(double, 9));
}

قبول FnMut

إذا احتاجت الدالة إلى تعديل الحالة الملتقطة، فاشترطوا FnMut وحددوا المعامل باستخدام mut.

fn call_twice<F: FnMut()>(mut f: F) {
    f();
    f();
}

fn main() {
    let mut total = 0;
    call_twice(|| total += 1);
    // note: total is borrowed during the call
}

قبول FnOnce

عندما تستدعي الدالة Closure مرة واحدة فقط وقد تتيح لها استهلاك القيم، فاشترطوا FnOnce.

fn run_once<F: FnOnce() -> String>(f: F) {
    let result = f();
    println!("{}", result);
}

fn main() {
    let s = String::from("done");
    run_once(move || s);
}

الكلمة المفتاحية move

تجبر الكلمة المفتاحية move Closure على تولي ملكية المتغيرات الملتقطة بدلًا من استعارتها.

وهذا ضروري عندما يجب أن يستمر عمر Closure بعد انتهاء النطاق الذي أُنشئت فيه، كما يحدث في الخيوط.

fn main() {
    let data = vec![1, 2, 3];
    let printer = move || println!("{:?}", data);
    printer();
}

كيف تختار Rust السمة

لا تختارون السمة يدويًا؛ إذ يحددها المترجم بناءً على جسم Closure:

  • القراءة فقط → Fn
  • التعديل → FnMut
  • نقل قيمة ملتقطة إلى الخارج → FnOnce
fn main() {
    let mut log = Vec::new();
    let mut record = |x: i32| log.push(x); // FnMut
    record(1);
    record(2);
    println!("{:?}", log);
}

اختيار القيد المناسب

كقاعدة عامة:

  • اقبلوا Fn عندما تحتاجون فقط إلى الاستدعاء والقراءة.
  • اقبلوا FnMut عندما تعدّل Closure الحالة.
  • اقبلوا FnOnce عندما يكفي الاستدعاء مرة واحدة.

اختاروا القيد الأكثر سماحًا الذي يفي بالغرض.

fn each<F: Fn(i32)>(items: &[i32], f: F) {
    for &i in items {
        f(i);
    }
}

fn main() {
    each(&[1, 2, 3], |n| println!("got {}", n));
}

تحقق سريع

طابقوا سلوك Closure مع سمتها.

مراجعة

سمات Closure الثلاث:

  • Fn — تستعير بشكل غير قابل للتغيير ويمكن استدعاؤها مرارًا.
  • FnMut — تستعير بشكل قابل للتغيير ويمكنها تغيير الحالة.
  • FnOnce — تتولى الملكية ويمكن استدعاؤها مرة واحدة.

يستنتج المترجم السمة؛ وتفرض move التقاط الملكية.

fn main() {
    let base = 5;
    let adder = move |x: i32| x + base; // Fn, captures base by move
    println!("{}", adder(10));
}

الأسئلة الشائعة

هل درس «Fn وFnMut وFnOnce» مجاني؟

نعم — نص درس «Fn وFnMut وFnOnce» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Learn Rust Coding، انتقل إلى CoddyKit PRO. تتضمن دورة Learn Rust Coding 4 دروس في المجموع.

ماذا ستتعلم في «Fn وFnMut وFnOnce»؟

سمات الإغلاق تتمرن على Learn Rust Coding مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Learn Rust Coding؟

لا تُشترط خبرة سابقة. Learn Rust Coding على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «Fn وFnMut وFnOnce»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Learn Rust Coding هذا؟

نعم. كل درس في Learn Rust Coding يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. تعريف الدوال
  2. التعبيرات والتعليمات
  3. الإغلاقات
  4. Fn وFnMut وFnOnce
← العودة إلى Learn Rust Coding