Skip to content

结构体语法

> 掌握结构体更新语法(..)、元组结构体和单元结构体的使用场景。

结构体更新语法

使用 .. 复制其他字段

rust
struct User {
    username: String,
    email: String,
    active: bool,
    sign_in_count: u64,
}

fn main() {
    let user1 = User {
        username: String::from("user1"),
        email: String::from("user1@example.com"),
        active: true,
        sign_in_count: 1,
    };

    // 基于 user1 创建 user2
    let user2 = User {
        email: String::from("user2@example.com"),  // 新值
        username: String::from("user2"),           // 新值
        ..user1  // 使用 user1 的其他字段(active, sign_in_count)
    };

    println!("user1: {} ({})", user1.username, user1.email);
    println!("user2: {} ({})", user2.username, user2.email);
    println!("user2 active: {}", user2.active);  // 从 user1 复制
}
▶ Run

所有权注意事项

rust
struct User {
    username: String,  // 不实现 Copy
    active: bool,      // 实现 Copy
}

fn main() {
    let user1 = User {
        username: String::from("alice"),
        active: true,
    };

    // 使用 .. 会移动非 Copy 字段
    let user2 = User {
        username: String::from("bob"),
        ..user1  // user1.username 被移动
    };

    // println!("{}", user1.username);  // ❌ 错误:已被移动
    println!("{}", user1.active);  // ✅ 正确:bool 实现 Copy
}
▶ Run

三种结构体形式

命名结构体(最常用)

rust
// 标准形式,字段有名字
struct Person {
    name: String,
    age: u32,
}

fn main() {
    let p = Person {
        name: String::from("Alice"),
        age: 25,
    };

    println!("{} 岁", p.age);  // 使用字段名访问
}
▶ Run

元组结构体(Tuple Struct)

rust
// 有结构体名字,但字段无名字
struct Color(i32, i32, i32);  // RGB
struct Point(i32, i32, i32);  // XYZ

fn main() {
    let black = Color(0, 0, 0);
    let origin = Point(0, 0, 0);

    // 使用索引访问
    println!("R 值:{}", black.0);
    println!("G 值:{}", black.1);
    println!("B 值:{}", black.2);

    println!("X 值:{}", origin.0);
    println!("Y 值:{}", origin.1);
    println!("Z 值:{}", origin.2);

    // 注意:虽然都是 (0,0,0),但类型不同
    // let p: Point = black;  // ❌ 错误:类型不同
}
▶ Run

元组结构体的使用场景

rust
// 场景 1:给元组添加语义
struct PhoneNumber(String);
struct Email(String);

fn main() {
    let phone = PhoneNumber(String::from("123-456-7890"));
    let email = Email(String::from("test@example.com"));

    // 类型安全:不能混用
    // let wrong: Email = phone;  // ❌ 错误
}

// 场景 2:新类型模式(类型安全)
struct Meters(f64);
struct Feet(f64);

fn print_distance(m: Meters) {
    println!("距离:{} 米", m.0);
}

fn main() {
    let m = Meters(100.0);
    let f = Feet(100.0);

    print_distance(m);  // ✅ 正确
    // print_distance(f);  // ❌ 错误:类型不同
}
▶ Run

单元结构体(Unit-like Struct)

rust
// 没有任何字段
struct AlwaysEqual;
struct Marker;
struct Config;

fn main() {
    let marker = Marker;  // 只有一个可能的值

    // 使用场景:
    // 1. 实现 Trait
    // 2. 类型标记
    // 3. 状态机
}
▶ Run

单元结构体的实际用途

rust
// 示例:实现 Trait
trait Handler {
    fn handle(&self, data: &str);
}

struct LogHandler;  // 单元结构体作为标记

impl Handler for LogHandler {
    fn handle(&self, data: &str) {
        println!("日志:{}", data);
    }
}

fn process(handler: &impl Handler, data: &str) {
    handler.handle(data);
}

fn main() {
    let handler = LogHandler;
    process(&handler, "处理数据");
}
▶ Run

小结

  • ..struct 更新语法:从其他实例复制未指定的字段
  • 元组结构体:有名字但字段无名字,用于类型安全的"新类型模式"
  • 单元结构体:无字段,用于实现 Trait 或类型标记
  • 使用 .. 时注意所有权:非 Copy 字段会被移动

练习题

详见:练习题