ฟังก์ชันแบบ泛用
กำหนดพฤติกรรมด้วยชนิดข้อมูล
ฟังก์ชันแบบ泛用 เป็นบทเรียน 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ