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

รูปแบบ Builder

สร้างออบเจ็กต์ทีละขั้นตอน

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

ทำไมต้องใช้ Builder

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

รูปแบบ builder แก้ปัญหานี้ได้ คุณกำหนดค่าออบเจ็กต์ทีละขั้นด้วยเมธอดที่มีชื่อชัดเจน แล้วเรียก build() ขั้นสุดท้ายเพื่อสร้างค่า โค้ดจึงอ่านต่อเนื่องเหมือนประโยค

โครงสร้างเป้าหมาย

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

สังเกตว่าฟิลด์ต่าง ๆ เป็นส่วนตัว เพื่อส่งเสริมให้สร้างค่าผ่าน builder แทนการใช้ลิเทอรัลของโครงสร้าง

pub struct ServerConfig {
    host: String,
    port: u16,
    max_connections: usize,
    use_tls: bool,
}

ชนิด Builder แยกต่างหาก

แนวทางคลาสสิกคือใช้โครงสร้างตัวที่สอง ซึ่งก็คือ builder โดยจะมีโครงสร้างคล้ายเป้าหมาย แต่เก็บสถานะระหว่างการสร้าง ฟิลด์ที่เป็นตัวเลือกมักเปลี่ยนเป็น Option<T> เพื่อแยกได้ว่า "ยังไม่ได้กำหนด" หรือ "กำหนดไว้อย่างชัดเจนแล้ว"

pub struct ServerConfigBuilder {
    host: String,
    port: Option<u16>,
    max_connections: Option<usize>,
    use_tls: bool,
}

เริ่มต้น Builder

สร้างคอนสตรักเตอร์ให้ builder โดยรับเฉพาะฟิลด์ที่จำเป็น ทุกตัวเลือกจะเริ่มต้นเป็น None หรือค่าเริ่มต้น

รูปแบบที่ใช้กันทั่วไปคือสร้างเมธอด builder() บนชนิดเป้าหมาย ซึ่งคืนค่า builder

impl ServerConfig {
    pub fn builder(host: impl Into<String>) -> ServerConfigBuilder {
        ServerConfigBuilder {
            host: host.into(),
            port: None,
            max_connections: None,
            use_tls: false,
        }
    }
}

เมธอด Setter รับ self ตามค่า

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

การต่อเมธอดโดยอาศัยความเป็นเจ้าของนี้เป็นรูปแบบ Rust ที่เหมาะสม และช่วยหลีกเลี่ยงปัญหายุ่งยากเกี่ยวกับอายุการใช้งาน

impl ServerConfigBuilder {
    pub fn port(mut self, port: u16) -> Self {
        self.port = Some(port);
        self
    }
    pub fn use_tls(mut self, yes: bool) -> Self {
        self.use_tls = yes;
        self
    }
}

ใช้ค่าเริ่มต้นใน build()

build() ขั้นสุดท้ายจะแปลง builder ให้เป็นชนิดจริง ตรงนี้เองที่คุณเติมค่าเริ่มต้นให้สิ่งที่ยังเป็น None โดยใช้ unwrap_or

impl ServerConfigBuilder {
    pub fn build(self) -> ServerConfig {
        ServerConfig {
            host: self.host,
            port: self.port.unwrap_or(8080),
            max_connections: self.max_connections.unwrap_or(128),
            use_tls: self.use_tls,
        }
    }
}

การสร้างแบบต่อเนื่อง

ตอนนี้ขั้นตอนการสร้างอ่านจากบนลงล่างได้ Required data จะถูกส่งเข้า builder() และการปรับตัวเลือกแต่ละอย่างจะเป็นการเรียกที่มีชื่อชัดเจน

ฟิลด์ที่คุณข้ามไปจะใช้ค่าเริ่มต้นโดยอัตโนมัติ

fn main() {
    let cfg = ServerConfig::builder("localhost")
        .port(9000)
        .use_tls(true)
        .build();
    println!("{}:{} tls={}", cfg.host, cfg.port, cfg.use_tls);
}

ตัวอย่างที่ทำงานได้อย่างสมบูรณ์

นี่คือรูปแบบทั้งหมดที่ย่อรวมเป็นโปรแกรมเดียวซึ่งคุณสามารถเรียกใช้ได้ ตัวอย่างแสดงให้เห็นว่าฟิลด์ที่ข้ามไปจะใช้ค่าเริ่มต้นภายใน build()

struct Config { name: String, retries: u32 }
struct Builder { name: String, retries: Option<u32> }
impl Config {
    fn builder(name: &str) -> Builder {
        Builder { name: name.to_string(), retries: None }
    }
}
impl Builder {
    fn retries(mut self, n: u32) -> Self { self.retries = Some(n); self }
    fn build(self) -> Config {
        Config { name: self.name, retries: self.retries.unwrap_or(3) }
    }
}
fn main() {
    let c = Config::builder("job").build();
    println!("{} retries={}", c.name, c.retries);
}

build ที่อาจล้มเหลวด้วย Result

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

impl ServerConfigBuilder {
    pub fn try_build(self) -> Result<ServerConfig, String> {
        let port = self.port.unwrap_or(8080);
        if port == 0 {
            return Err("port must be non-zero".into());
        }
        Ok(ServerConfig { host: self.host, port,
            max_connections: self.max_connections.unwrap_or(128),
            use_tls: self.use_tls })
    }
}

ครেট derive_builder

การเขียน builder ด้วยตนเองซ้ำซาก ครेट derive_builder สามารถสร้าง builder ทั้งหมดจากคำอธิบายกำกับ

คุณใส่คำอธิบายกำกับให้ฟิลด์พร้อมค่าเริ่มต้น แล้วจะได้ FooBuilder ที่สร้างขึ้นโดยอัตโนมัติ พร้อม setter และ build() ที่อาจล้มเหลว โดยไม่ต้องเขียนโค้ดเพิ่มเติม

use derive_builder::Builder;

#[derive(Builder)]
struct Channel {
    #[builder(default = "8080")]
    port: u16,
    name: String,
}

Builder แบบเป็นเจ้าของข้อมูลเทียบกับแบบอ้างอิงที่แก้ไขได้

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

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

impl ServerConfigBuilder {
    pub fn port_ref(&mut self, port: u16) -> &mut Self {
        self.port = Some(port);
        self
    }
}

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

ทดสอบความเข้าใจของคุณเกี่ยวกับรูปแบบ builder ที่ใช้ self ซึ่งเป็นเจ้าของข้อมูล

สรุป

รูปแบบ builder ช่วยแก้ข้อจำกัดที่ Rust ไม่มีอาร์กิวเมนต์แบบตัวเลือก ชนิด builder จะเก็บสถานะระหว่างการสร้าง setter จะใช้และคืนค่า self เพื่อให้ต่อเมธอดได้ และ build() จะใช้ค่าเริ่มต้นเพื่อสร้างค่าสุดท้าย

ใช้ Result จาก build() สำหรับการตรวจสอบความถูกต้อง และเลือกใช้ derive_builder เพื่อไม่ต้องเขียนโค้ดซ้ำซาก

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

บทเรียน “รูปแบบ Builder” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “รูปแบบ Builder”

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

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

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

บทเรียน “รูปแบบ Builder” ใช้เวลานานแค่ไหน

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

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

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

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

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