0Pricing
Learn Rust Coding · บทเรียน

Fn, FnMut, FnOnce

คุณลักษณะของคลอเชอร์

Fn, FnMut, FnOnce เป็นบทเรียน Learn Rust Coding ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 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 เพียงครั้งเดียวและอาจให้ 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” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Learn Rust Coding ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Learn Rust Coding มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “Fn, FnMut, FnOnce”

คุณลักษณะของคลอเชอร์ คุณปฏิบัติ Learn Rust Coding ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Learn Rust Coding หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Learn Rust Coding บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “Fn, FnMut, FnOnce” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Learn Rust Coding นี้ได้ไหม

ได้ บทเรียน Learn Rust Coding ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การกำหนดฟังก์ชัน
  2. นิพจน์และคำสั่ง
  3. คลอเชอร์
  4. Fn, FnMut, FnOnce
← กลับไปที่ Learn Rust Coding