Learn Rust Coding · บทเรียน

ความสะดวกของ Deref และตัวห่อหุ้ม

ทำให้ตัวห่อหุ้มใช้งานได้เหมือนชนิดข้อมูลพื้นฐาน

บทเรียน 4 จาก 413 ขั้นตอน

ความสะดวกของ Deref และตัวห่อหุ้ม เป็นบทเรียน Learn Rust Coding ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Learn Rust Coding และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Learn Rust Coding มีบทเรียนทั้งหมด 4 บทเรียน

ปัญหาด้านความสะดวกในการใช้งาน

การห่อชนิดข้อมูลด้วย newtype เพิ่มความปลอดภัยแต่ลดความสะดวกลง ทันใดนั้นคุณต้องเขียน wrapper.0.method() ในทุกที่ และเขียนเมธอดขึ้นใหม่เอง

trait Deref ช่วยคืนความสะดวกในการใช้งานส่วนใหญ่ได้ โดยทำให้ wrapper ทำงานเหมือนค่าที่มันเก็บไว้

Deref ทำอะไร

Deref กำหนดว่าสิ่งที่ *value จะสร้างขึ้นคืออะไร และขับเคลื่อนตัวดำเนินการ . เมื่อคุณเรียกเมธอดที่ wrapper ไม่มี คอมไพเลอร์จะลองเรียกอีกครั้งกับเป้าหมายของการ deref

ขั้นตอนอัตโนมัตินี้เรียกว่าการบังคับชนิดด้วย deref

use std::ops::Deref;
struct MyBox<T>(T);
impl<T> Deref for MyBox<T> {
    type Target = T;
    fn deref(&self) -> &T { &self.0 }
}

การบังคับชนิดด้วย Deref ในการทำงาน

เมื่อ implement Deref แล้ว การเรียกเมธอดของค่าภายในผ่าน wrapper ก็ทำงานได้ทันที คอมไพเลอร์จะแทรก .deref() ให้คุณจนกว่าจะพบเมธอด

use std::ops::Deref;
struct Name(String);
impl Deref for Name {
    type Target = String;
    fn deref(&self) -> &String { &self.0 }
}
fn main() {
    let n = Name("rustacean".to_string());
    println!("len = {}", n.len()); // String::len via deref
}

DerefMut สำหรับการเข้าถึงแบบเปลี่ยนแปลงได้

Deref ให้การเข้าถึงแบบใช้ร่วมกันเท่านั้น หากต้องการเรียกเมธอดที่ต้องใช้ &mut self ผ่าน wrapper ให้ implement DerefMut เพิ่มด้วย ซึ่งจะคืนค่าการอ้างอิงที่เปลี่ยนแปลงค่าของข้อมูลภายในได้

use std::ops::{Deref, DerefMut};
struct Stack(Vec<i32>);
impl Deref for Stack {
    type Target = Vec<i32>;
    fn deref(&self) -> &Vec<i32> { &self.0 }
}
impl DerefMut for Stack {
    fn deref_mut(&mut self) -> &mut Vec<i32> { &mut self.0 }
}

การบังคับชนิดที่ขอบเขตฟังก์ชัน

การบังคับชนิดด้วย deref ยังใช้กับอาร์กิวเมนต์ได้ด้วย &Name จะถูกบังคับชนิดเป็น &String และสิ่งนี้เองจะถูกบังคับชนิดต่อเป็น &str ดังนั้นคุณจึงส่ง wrapper เข้าไปในฟังก์ชันที่ต้องการการอ้างอิงของค่าภายในได้โดยตรง

fn greet(who: &str) {
    println!("hi {}", who);
}
// greet(&name) works: &Name -> &String -> &str

ตัวอย่างการบังคับชนิดที่เรียกใช้งานได้

โปรแกรมนี้ส่งการอ้างอิงไปยัง wrapper ในตำแหน่งที่ต้องการสไลซ์ของสตริง การบังคับชนิดด้วย deref ที่ต่อเนื่องกันจะเกิดขึ้นอย่างเงียบ ๆ ณ จุดเรียกใช้

use std::ops::Deref;
struct Tag(String);
impl Deref for Tag {
    type Target = String;
    fn deref(&self) -> &String { &self.0 }
}
fn shout(s: &str) { println!("{}!", s.to_uppercase()); }
fn main() {
    let t = Tag("ship".to_string());
    shout(&t);
}

อย่าใช้ Deref ในทางที่ผิด

แนวทาง API ของ Rust เตือนไม่ให้ implement Deref กับชนิดข้อมูลที่ไม่ใช่พอยน์เตอร์อัจฉริยะอย่างแท้จริง การใช้มากเกินไปทำให้เมธอดที่ wrapper มีให้ใช้งานคาดเดาได้ยาก และทำให้ผู้อ่านประหลาดใจ

หาก newtype มีไว้เพื่อจำกัด API การใช้ Deref แบบครอบคลุมอาจเปิดเผยเมธอดที่คุณตั้งใจซ่อนไว้พอดี

AsRef เป็นทางเลือกแบบเจาะจง

เมื่อคุณต้องการการแปลงอย่างชัดเจนแทนการบังคับชนิดโดยอัตโนมัติ ให้ implement AsRef ผู้เรียกจะเขียน .as_ref() อย่างตั้งใจ ทำให้ขอบเขต API ของ wrapper เองยังชัดเจน

struct Path(String);
impl AsRef<str> for Path {
    fn as_ref(&self) -> &str { &self.0 }
}

การส่งต่อเมธอดที่เลือกไว้

สำหรับ wrapper ที่มีข้อจำกัด ควรเขียนเฉพาะเมธอดที่ต้องการเปิดเผยด้วยตนเอง วิธีนี้ช่วยให้ควบคุม API ได้อย่างเต็มที่ แทนที่จะเปิดเผยทุกอย่างผ่าน Deref

struct Counter(Vec<u8>);
impl Counter {
    fn len(&self) -> usize { self.0.len() }
    fn push(&mut self, b: u8) { self.0.push(b); }
}

พอยน์เตอร์อัจฉริยะใช้ Deref

พอยน์เตอร์อัจฉริยะมาตรฐานอย่าง Box, Rc และ Arc ล้วน implement Deref นั่นจึงเป็นเหตุผลที่คุณเรียกเมธอดของค่าภายในได้โดยไม่ต้องเขียนอะไรเพิ่ม นี่คือการใช้ trait นี้อย่างถูกต้องและตรงตามจุดประสงค์

use std::rc::Rc;
fn main() {
    let shared = Rc::new(String::from("data"));
    // Deref lets us call String methods directly
    println!("len = {}", shared.len());
}

การเลือกกลยุทธ์ด้านความสะดวกในการใช้งาน

เลือกตามจุดประสงค์ ใช้ Deref สำหรับ wrapper ที่เป็นพอยน์เตอร์อัจฉริยะอย่างแท้จริง ใช้ AsRef สำหรับการแปลงการยืมอย่างชัดเจน และใช้การส่งต่อด้วยตนเองเมื่อ newtype ต้องจำกัด API ของชนิดข้อมูลภายใน

การเลือกผิดจะทำให้ซ่อนมากเกินไปหรือเปิดเผยม​​ากเกินไป

ตรวจสอบความเข้าใจอย่างรวดเร็ว

พิจารณาว่า wrapper ใดเหมาะสมกับการ implement Deref

สรุปทบทวน

Deref และการบังคับชนิดด้วย deref ช่วยคืนความสะดวกให้ wrapper โดยทำให้ตัวดำเนินการ . และอาร์กิวเมนต์ที่เป็นการอ้างอิงส่งต่อไปยังค่าภายในได้ ส่วน DerefMut จะเพิ่มการเข้าถึงแบบเปลี่ยนแปลงได้

ควรใช้ Deref กับพอยน์เตอร์อัจฉริยะอย่างแท้จริงเท่านั้น สำหรับ newtype ที่มีข้อจำกัด ให้ใช้ AsRef เพื่อการแปลงอย่างชัดเจน หรือส่งต่อเฉพาะเมธอดที่คุณเลือกเปิดเผย

เริ่มต้นได้ฟรี

เรียนรู้ Rust ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
39
บทเรียน
144

คำถามที่พบบ่อย

บทเรียน “ความสะดวกของ Deref และตัวห่อหุ้ม” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “ความสะดวกของ Deref และตัวห่อหุ้ม” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Learn Rust Coding ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Learn Rust Coding มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “ความสะดวกของ Deref และตัวห่อหุ้ม”

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

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

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

บทเรียน “ความสะดวกของ Deref และตัวห่อหุ้ม” ใช้เวลานานแค่ไหน

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

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

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

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

  1. รูปแบบ Builder
  2. รูปแบบ Newtype
  3. Builder ที่มีสถานะตามชนิดข้อมูล
  4. ความสะดวกของ Deref และตัวห่อหุ้ม
← กลับไปที่ Learn Rust Coding