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

ขอบเขตของ trait

จำกัด泛型ด้วย trait

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

หน้าที่ของข้อจำกัด Trait

ข้อจำกัดของ trait จะจำกัดชนิดข้อมูลเจเนอริกให้เหลือเฉพาะชนิดที่ใช้ trait ที่กำหนดได้ โดยบอกคอมไพเลอร์ว่าชนิดข้อมูลนั้นรับรองพฤติกรรมใด

วิธีนี้ทำให้ใช้เมธอดของ trait ภายในโค้ดเจเนอริกได้ พร้อมทั้งยังคงใช้ฟังก์ชันกับชนิดข้อมูลได้หลายชนิด

ไวยากรณ์ข้อจำกัดแบบแทรกในบรรทัด

รูปแบบที่ง่ายที่สุดคือวางข้อจำกัดไว้ถัดจากพารามิเตอร์ชนิดข้อมูล: T: Trait ในที่นี้ T ต้องใช้ Display ได้ เพื่อให้พิมพ์ค่าได้

ภายในฟังก์ชัน ตอนนี้คุณสามารถเรียกใช้เมธอดใด ๆ ที่ Display มีให้

use std::fmt::Display;

fn show<T: Display>(value: T) {
    println!("value = {}", value);
}

Trait ที่กำหนดเอง

ข้อจำกัดใช้กับ trait ของคุณเองได้เช่นกัน กำหนด trait พร้อมเมธอด แล้วกำหนดให้ฟังก์ชันเจเนอริกมีข้อจำกัดเป็น trait นั้น

trait Summary นี้กำหนดให้ต้องมีเมธอด summarize ที่คืนค่าสตริง

trait Summary {
    fn summarize(&self) -> String;
}

การนำไปใช้และการกำหนดข้อจำกัด

นำ trait ไปใช้กับชนิดข้อมูลหนึ่ง จากนั้นฟังก์ชันที่มีข้อจำกัดจะรับชนิดข้อมูลใด ๆ ที่นำ trait นี้ไปใช้ได้ ฟังก์ชันจะเรียกเมธอดของ trait โดยไม่จำเป็นต้องรู้ชนิดข้อมูลจริง

โปรแกรมฉบับเต็มนี้พิมพ์บทสรุปของ Article

trait Summary { fn summarize(&self) -> String; }

struct Article { title: String }

impl Summary for Article {
    fn summarize(&self) -> String {
        format!("Article: {}", self.title)
    }
}

fn notify<T: Summary>(item: &T) {
    println!("{}", item.summarize());
}

fn main() {
    let a = Article { title: String::from("Rust") };
    notify(&a);
}

การรวมข้อจำกัดด้วย +

กำหนดให้ต้องใช้หลาย trait พร้อมกันด้วยการเชื่อมด้วย + ในที่นี้ T ต้องใช้ทั้ง Display และ Clone ได้

จากนั้นฟังก์ชันจะพิมพ์ค่าและโคลนค่าได้ด้วย

use std::fmt::Display;

fn process<T: Display + Clone>(value: T) {
    let copy = value.clone();
    println!("{}", copy);
}

impl Trait ในอาร์กิวเมนต์

ไวยากรณ์ impl Trait ในตำแหน่งอาร์กิวเมนต์เป็นรูปแบบย่อของข้อกำหนดอย่างง่าย item: &impl Summary มีความหมายเหมือนพารามิเตอร์แบบ <T: Summary>

รูปแบบนี้กระชับสำหรับกรณีที่มีอาร์กิวเมนต์เดียว แต่ควบคุมการนำชนิดไปใช้ซ้ำได้น้อยกว่า

trait Summary { fn summarize(&self) -> String; }

fn notify(item: &impl Summary) {
    println!("{}", item.summarize());
}

การคืนค่า impl Trait

คุณสามารถคืนค่า impl Trait เพื่อซ่อนชนิดที่เป็นรูปธรรม พร้อมรับรองว่าชนิดนั้นใช้งานเทรตดังกล่าวได้ วิธีนี้มีประโยชน์กับคลอเชอร์และตัววนซ้ำ

ผู้เรียกจะทราบเพียงว่าผลลัพธ์ใช้งานเทรตที่ระบุได้

fn make_adder(n: i32) -> impl Fn(i32) -> i32 {
    move |x| x + n
}

fn main() {
    let add5 = make_adder(5);
    println!("{}", add5(10));
}

ข้อกำหนดเปิดใช้ตัวดำเนินการ

ตัวดำเนินการจะสอดคล้องกับเทรต ได้แก่ + ต้องใช้ Add, == ต้องใช้ PartialEq และการเปรียบเทียบต้องใช้ PartialOrd การกำหนดขอบเขตด้วยเทรตเหล่านี้ทำให้โค้ดทั่วไปใช้ตัวดำเนินการได้

ในที่นี้ การหาผลรวมกำหนดให้ T ต้องใช้งาน Add กับตัวมันเองได้

use std::ops::Add;

fn sum<T: Add<Output = T>>(a: T, b: T) -> T {
    a + b
}

เมธอดเริ่มต้นของเทรต

เทรตสามารถจัดเตรียมตัวเมธอดเริ่มต้นได้ ผู้ใช้งานเทรตอาจเขียนทับเมธอดเหล่านั้น หรือใช้ค่าเริ่มต้นต่อไปก็ได้ เจเนอริกที่มีข้อกำหนดจะใช้เมธอดที่มีผลอยู่ในขณะนั้น

Summary นี้มี summarize เป็นค่าเริ่มต้น ซึ่งชนิดต่าง ๆ สามารถคงไว้ตามเดิมได้

trait Summary {
    fn summarize(&self) -> String {
        String::from("(no summary)")
    }
}

struct Note;
impl Summary for Note {}

การเรียกใช้แบบสแตติกเทียบกับแบบไดนามิก

ข้อกำหนดเทรตใช้การเรียกใช้แบบสแตติก โดยคอมไพเลอร์จะเลือกเมธอดที่แน่นอนในเวลาคอมไพล์ผ่านการสร้างโค้ดเฉพาะชนิด ตรงกันข้าม dyn Trait ใช้การเรียกใช้แบบไดนามิกผ่านตารางเสมือน

โดยทั่วไปข้อกำหนดจะทำงานเร็วกว่า ส่วน dyn แลกความเร็วกับไบนารีที่มีขนาดเล็กลงและความยืดหยุ่นขณะทำงาน

ข้อกำหนดบนโครงสร้างข้อมูลเจเนอริก

ข้อกำหนดเทรตไม่ได้จำกัดอยู่แค่ฟังก์ชัน คุณสามารถกำหนดข้อกำหนดขณะประกาศโครงสร้างข้อมูล เพื่อให้ทุกอินสแตนซ์ใช้งานเทรตนั้นได้

ในที่นี้ Sortable<T> ทุกตัวรับรองว่าสามารถเปรียบเทียบสมาชิกของตนได้

struct Sortable<T: PartialOrd> {
    items: Vec<T>,
}

ตรวจสอบความเข้าใจ

ทดสอบความเข้าใจของคุณเกี่ยวกับข้อกำหนดเทรต

สรุปทบทวน

ข้อกำหนดเทรตจำกัดชนิดเจเนอริก เพื่อให้คอมไพเลอร์อนุญาตให้ใช้เมธอดและตัวดำเนินการของเทรตนั้นได้ คุณสามารถรวมเทรตด้วย + และใช้ impl Trait เป็นรูปแบบย่อในอาร์กิวเมนต์หรือค่าที่คืนกลับ

ข้อกำหนดให้การเรียกใช้แบบสแตติกโดยไม่มีค่าใช้จ่ายเพิ่มเติม ต่างจากการเรียกใช้แบบไดนามิกของ dyn Trait

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

บทเรียน “ขอบเขตของ trait” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “ขอบเขตของ trait”

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

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

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

บทเรียน “ขอบเขตของ trait” ใช้เวลานานแค่ไหน

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

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

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

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

  1. ฟังก์ชันแบบ泛用
  2. struct และ enum แบบ泛用
  3. ขอบเขตของ trait
  4. อนุประโยค where และขอบเขตหลายรายการ
← กลับไปที่ Learn Rust Coding