Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

English Original

构造器模式

你将学到什么: 如何在没有传统构造函数语法的情况下创建 Rust 结构体,包括 new() 约定、Default trait、工厂方法,以及用于复杂初始化的 builder 模式。

难度: 🟢 初级

C# 与 Rust 的构造器对比

在 C# 中,构造函数是具有特定名称(与类名相同)的方法。Rust 则使用了在约定上返回结构体类型的关联函数

C# 构造函数

public class Config {
    public string Url { get; set; }
    public Config(string url) { Url = url; }
}

Rust 构造函数约定

#![allow(unused)]
fn main() {
pub struct Config {
    pub url: String,
}

impl Config {
    // Rust 中并没有特殊的 'constructor' 关键字。
    // 'new' 只是一个在约定俗成下被广泛使用的普通函数名。
    pub fn new(url: String) -> Self {
        Self { url }
    }
}
}

Default Trait

Default trait 是为某种类型提供默认值的标准方式(类似于 C# 中的无参数构造函数)。

#![allow(unused)]
fn main() {
#[derive(Default)]
pub struct Options {
    pub port: u32,       // 默认值为 0
    pub logging: bool,   // 默认值为 false
}

let opt = Options::default();
}

Builder 模式

对于具有许多可选参数的复杂对象,Rust 开发者更倾向于使用 Builder 模式,而不是构造函数重载。

#![allow(unused)]
fn main() {
pub struct Server {
    host: String,
    port: u16,
}

pub struct ServerBuilder {
    host: Option<String>,
    port: u16,
}

impl ServerBuilder {
    pub fn new() -> Self {
        Self { host: None, port: 8080 }
    }

    pub fn host(mut self, host: String) -> Self {
        self.host = Some(host);
        self
    }

    pub fn build(self) -> Result<Server, String> {
        let host = self.host.ok_or("必须提供 Host")?;
        Ok(Server { host, port: self.port })
    }
}

// 使用示例
let server = ServerBuilder::new()
    .host("localhost".to_string())
    .build()?;
}

核心优势: Builder 模式是类型安全的,且能有效避免编写具有十几个参数的超长构造函数。


练习:Email 构造器

挑战: 创建一个 EmailBuilder,要求 tosubject 是强制性的,而 body 是可选的。

#![allow(unused)]
fn main() {
struct Email {
    to: String,
    subject: String,
    body: Option<String>,
}

struct EmailBuilder {
    to: Option<String>,
    subject: Option<String>,
    body: Option<String>,
}

impl EmailBuilder {
    fn build(self) -> Result<Email, String> {
        let to = self.to.ok_or("缺少收信人")?;
        let subject = self.subject.ok_or("缺少主题")?;
        Ok(Email { to, subject, body: self.body })
    }
}
}

要点: Rust 中的 Builder 模式通常利用 Result 来返回一个完整合法的对象或一个详细的错误说明。