ความสะดวกของ Deref และตัวห่อหุ้ม
ทำให้ตัวห่อหุ้มใช้งานได้เหมือนชนิดข้อมูลพื้นฐาน
ความสะดวกของ 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- รูปแบบ Builder
- รูปแบบ Newtype
- Builder ที่มีสถานะตามชนิดข้อมูล
- ความสะดวกของ Deref และตัวห่อหุ้ม