Closures
Closure คืออะไร?
หัวข้อที่มีชื่อว่า “Closure คืออะไร?”Closure คือ Function นิรนามที่กำหนด Inline ด้วย Syntax |params| body ต่างจาก fn ทั่วไป Closure สามารถ จับ (Capture) ตัวแปรจาก Scope ที่ล้อมรอบได้
let multiplier = 3;let triple = |x| x * multiplier; // จับ multiplier จาก Environmentprintln!("{}", triple(7)); // 21การจับ Environment
หัวข้อที่มีชื่อว่า “การจับ Environment”Rust มี Trait สำหรับ Closure สามแบบที่อธิบายว่า Closure ใช้ค่าที่จับไว้อย่างไร:
| Trait | วิธีการจับ | สามารถเรียกได้ |
|---|---|---|
Fn | ยืมแบบ Immutable (&T) | กี่ครั้งก็ได้ |
FnMut | ยืมแบบ Mutable (&mut T) | กี่ครั้งก็ได้ |
FnOnce | รับ Ownership (T) | ครั้งเดียวเท่านั้น |
ทุก Closure Implement FnOnce เป็นอย่างน้อย ถ้า Closure แค่ยืมค่า ก็จะ Implement Fn ด้วย
Fn — ยืมแบบ Immutable
หัวข้อที่มีชื่อว่า “Fn — ยืมแบบ Immutable”fn apply<F: Fn(i32) -> i32>(f: F, x: i32) -> i32 { f(x) }
let base = 10;let add_base = |x| x + base; // ยืม base แบบ Immutableprintln!("{}", apply(add_base, 5)); // 15FnMut — ยืมแบบ Mutable
หัวข้อที่มีชื่อว่า “FnMut — ยืมแบบ Mutable”let mut count = 0;let mut increment = || { count += 1; count };println!("{}", increment()); // 1println!("{}", increment()); // 2drop(increment); // ปล่อย Mutable Borrow ก่อนอ่าน countprintln!("count is {}", count); // 2ต้องเรียก drop(increment) ก่อนอ่าน count โดยตรง เพราะ increment ถือ &mut count ที่จะขัดแย้งกับ Immutable Borrow ใน println!
FnOnce — รับ Ownership
หัวข้อที่มีชื่อว่า “FnOnce — รับ Ownership”let name = String::from("Rust");let greet = || println!("Hello, {}!", name); // ย้าย name เข้า Closuregreet(); // name ถูก Consume ที่นี่// greet(); // Compile Error — FnOnce เรียกได้แค่ครั้งเดียวKeyword move
หัวข้อที่มีชื่อว่า “Keyword move”move บังคับให้ Closure รับ Ownership ของตัวแปรที่จับทั้งหมด ไม่ว่าจะยืมเพียงอย่างเดียวก็ตาม:
let message = String::from("hi");let say = move || println!("{}", message); // message ถูกย้ายเข้า say// println!("{}", message); // error — message ถูกย้ายไปแล้วsay();move จำเป็นเมื่อ Closure มีอายุยาวกว่า Scope ที่กำหนด (เช่น ส่งไปยัง Thread)
Closures เป็น Iterator Adaptor
หัวข้อที่มีชื่อว่า “Closures เป็น Iterator Adaptor”Iterator Adaptor เช่น map และ filter รับ Closure โดยตรง:
let threshold = 3;let big: Vec<i32> = vec![1, 2, 3, 4, 5] .iter() .filter(|&&x| x > threshold) // Closure จับ threshold ด้วย & .map(|&x| x * 10) .collect();// [40, 50]fn apply<F: Fn(i32) -> i32>(f: F, x: i32) -> i32 { f(x)}
fn apply_mut<F: FnMut() -> i32>(mut f: F) -> i32 { f() + f()}
fn apply_once<F: FnOnce() -> String>(f: F) -> String { f()}
fn main() { // Fn: borrows environment immutably let multiplier = 3; let triple = |x| x * multiplier; println!("apply triple to 5: {}", apply(triple, 5));
// FnMut: captures and mutates let mut count = 0; let mut increment = || { count += 1; count }; let result = apply_mut(&mut increment); drop(increment); // release mutable borrow before reading count println!("FnMut result: {}, count is now: {}", result, count);
// FnOnce + move: takes ownership let name = String::from("Rust"); let greeting = move || format!("Hello, {}!", name); println!("{}", apply_once(greeting));
// closures as iterator adaptors let nums = vec![1, 2, 3, 4, 5]; let threshold = 3; let big: Vec<i32> = nums .iter() .filter(|&&x| x > threshold) .map(|&x| x * 10) .collect(); println!("big: {:?}", big);}Compiling…