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

ฟังก์ชันแบบ泛用

กำหนดพฤติกรรมด้วยชนิดข้อมูล

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

เหตุผลที่ใช้ฟังก์ชันเจเนอริก

ฟังก์ชันเจเนอริกช่วยให้คุณเขียนฟังก์ชันเดียวที่ทำงานกับหลายชนิดข้อมูล แทนการคัดลอกโค้ดสำหรับแต่ละชนิด Rust จะแทนที่ชนิดข้อมูลตัวแทนขณะคอมไพล์

ลองนึกภาพการเขียน largest สำหรับจำนวนเต็มหนึ่งฟังก์ชัน และอีกฟังก์ชันสำหรับ chars เจเนอริกจะรวมทั้งสองแบบเป็นคำจำกัดความเดียวโดยไม่มีต้นทุนขณะรันไทม์

พารามิเตอร์ชนิดข้อมูล

ฟังก์ชันเจเนอริกประกาศพารามิเตอร์ชนิดข้อมูลไว้ภายในเครื่องหมายแหลมหลังชื่อ ชื่อ T เป็นธรรมเนียมที่นิยมใช้ แต่คุณสามารถใช้ตัวระบุ CamelCase ใด ๆ ก็ได้

จากนั้นพารามิเตอร์นี้สามารถปรากฏในอาร์กิวเมนต์และชนิดข้อมูลที่คืนค่า โดยทำหน้าที่แทนชนิดข้อมูลจริงที่ผู้เรียกใช้กำหนด

fn first<T>(pair: (T, T)) -> T {
    pair.0
}

ฟังก์ชันเอกลักษณ์อย่างง่าย

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

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

fn echo<T>(value: T) -> T {
    value
}

fn main() {
    println!("{}", echo(42));
    println!("{}", echo("hi"));
}

การทำให้เป็นชนิดเดียว

Rust ใช้การทำให้เป็นชนิดเดียว: ขณะคอมไพล์ ระบบจะสร้างสำเนาฟังก์ชันเฉพาะสำหรับชนิดข้อมูลจริงแต่ละชนิดที่ใช้ ไม่มีการห่อกล่องหรือการเรียกแบบเสมือน

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

เจเนอริกต้องมีข้อจำกัด

ภายในฟังก์ชันเจเนอริก คุณใช้ได้เฉพาะการดำเนินการที่ชนิดข้อมูลที่เป็นไปได้ทุกชนิดรองรับเท่านั้น T เปล่า ๆ ไม่สามารถนำไปบวก เปรียบเทียบ หรือพิมพ์ได้

โค้ดนี้คอมไพล์ไม่สำเร็จ เพราะ T อาจไม่รองรับการเปรียบเทียบ เราจะแก้ไขด้วยข้อจำกัดของ trait ในหัวข้อถัดไป

fn larger<T>(a: T, b: T) -> T {
    if a > b { a } else { b }
}

การเพิ่มข้อจำกัดของ Trait

หากต้องการเปรียบเทียบค่า เราจะจำกัด T ด้วย PartialOrd ข้อจำกัดนี้รับรองว่าชนิดข้อมูลรองรับตัวดำเนินการ >

นอกจากนี้เรายังเพิ่ม Copy เพื่อให้คืนค่าได้โดยไม่มีปัญหาการย้าย สำหรับชนิดข้อมูลอย่างง่าย เช่น จำนวนเต็ม

fn larger<T: PartialOrd + Copy>(a: T, b: T) -> T {
    if a > b { a } else { b }
}

การเรียกใช้ฟังก์ชันที่มีข้อจำกัด

ตอนนี้ฟังก์ชันทำงานกับชนิดข้อมูลใด ๆ ที่ใช้ trait ทั้งสองได้ จำนวนเต็มและจำนวนทศนิยมต่างก็รองรับ PartialOrd + Copy

ซอร์สโค้ดเดียวกันซึ่งถูกทำให้เป็นชนิดเดียวเป็นสองเวอร์ชัน จะพิมพ์ผลลัพธ์สำหรับการเรียกใช้แต่ละครั้ง

fn larger<T: PartialOrd + Copy>(a: T, b: T) -> T {
    if a > b { a } else { b }
}

fn main() {
    println!("{}", larger(3, 9));
    println!("{}", larger(2.5, 1.0));
}

พารามิเตอร์ชนิดข้อมูลหลายตัว

ฟังก์ชันสามารถประกาศพารามิเตอร์ชนิดข้อมูลได้หลายตัว แต่ละตัวเป็นอิสระต่อกัน ดังนั้นอาร์กิวเมนต์ทั้งสองจึงอาจมีชนิดข้อมูลต่างกัน

ในที่นี้ pair รับ T ใด ๆ และ U ใด ๆ แล้วคืนค่าทั้งสองเป็นทูเพิล

fn pair<T, U>(a: T, b: U) -> (T, U) {
    (a, b)
}

การพิมพ์ค่าเจเนอริก

หากต้องการพิมพ์ค่าเจเนอริกด้วย {} ชนิดข้อมูลนั้นต้องใช้ Display ได้ เราจึงเพิ่มข้อจำกัดนี้ เพื่อให้ส่งชนิดข้อมูลใด ๆ ที่พิมพ์ได้เข้ามา

โค้ดนี้ติดป้ายกำกับค่าแล้วคืนค่าดังกล่าว เพื่อสาธิตการใช้ข้อจำกัดเฉพาะสำหรับการจัดรูปแบบ

use std::fmt::Display;

fn announce<T: Display>(label: &str, value: T) {
    println!("{}: {}", label, value);
}

fn main() {
    announce("count", 7);
    announce("name", "Ada");
}

ไวยากรณ์ Turbofish

บางครั้งคอมไพเลอร์ไม่สามารถอนุมาน T จากอาร์กิวเมนต์เพียงอย่างเดียวได้ ไวยากรณ์ turbofish ::<Type> ช่วยให้คุณระบุชนิดข้อมูลอย่างชัดเจน ณ จุดเรียกใช้

มักใช้กับเมธอดอย่าง parse และ collect ซึ่งชนิดข้อมูลที่คืนค่ามีความกำกวม

fn main() {
    let n = "42".parse::<i32>().unwrap();
    println!("{}", n + 1);
}

เจเนอริกกับรีเฟอเรนซ์

พารามิเตอร์เจเนอริกใช้กับรีเฟอเรนซ์ได้เช่นกัน การจำกัดผ่านรีเฟอเรนซ์ช่วยหลีกเลี่ยงการกำหนดให้ต้องใช้ Copy เมื่อคุณเพียงต้องการอ่านค่า

ตัวช่วยรูปแบบ longest_str นี้ยืมส่วนย่อยสองส่วนและคืนค่าส่วนหนึ่ง โดยไม่รับความเป็นเจ้าของ

fn pick<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> &'a T {
    if a > b { a } else { b }
}

ตรวจสอบอย่างรวดเร็ว

ทดสอบความเข้าใจเกี่ยวกับฟังก์ชันเจเนอริกใน Rust

สรุปทบทวน

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

การดำเนินการกับชนิดข้อมูลเจเนอริกต้องมีข้อจำกัดของ trait เช่น PartialOrd Copy หรือ Display ใช้ turbofish เมื่อการอนุมานไม่สามารถระบุชนิดข้อมูลได้

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

บทเรียน “ฟังก์ชันแบบ泛用” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “ฟังก์ชันแบบ泛用”

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

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

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

บทเรียน “ฟังก์ชันแบบ泛用” ใช้เวลานานแค่ไหน

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

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

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

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

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