核心特性

第8课:结构体与方法

🎯 本课目标

掌握Rust结构体定义、方法、关联函数、派生宏和可见性控制。

1. 三种结构体

// 1. 命名字段结构体(最常用)
struct User {
    name: String,
    email: String,
    age: u32,
    active: bool,
}

// 2. 元组结构体
struct Color(u8, u8, u8);
struct Point3D(f64, f64, f64);

// 3. 单元结构体
struct AlwaysEqual;

fn main() {
    let user = User {
        name: String::from("Alice"),
        email: String::from("alice@ex.com"),
        age: 30,
        active: true,
    };

    let red = Color(255, 0, 0);
    println!("R: {}", red.0);

    // 字段初始化简写 + 结构体更新
    let name = String::from("Bob");
    let user2 = User { name, ..user };  // String被移动!
}

✅ 编译验证通过

⚠️ ..user会移动非Copy字段。之后user的String字段不可用,但u32/bool等Copy字段仍可用。

2. 方法与关联函数

struct Rectangle { width: f64, height: f64 }

impl Rectangle {
    // 关联函数(无self,类似静态方法)
    pub fn new(width: f64, height: f64) -> Self {
        Self { width, height }
    }
    pub fn square(size: f64) -> Self {
        Self { width: size, height: size }
    }

    // &self: 只读借用
    pub fn area(&self) -> f64 {
        self.width * self.height
    }
    pub fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }

    // &mut self: 可变借用
    pub fn scale(&mut self, factor: f64) {
        self.width *= factor;
        self.height *= factor;
    }

    // self: 获取所有权
    pub fn into_tuple(self) -> (f64, f64) {
        (self.width, self.height)
    }
}

fn main() {
    let mut r = Rectangle::new(10.0, 20.0);
    println!("面积: {}", r.area());
    r.scale(2.0);
    let sq = Rectangle::square(5.0);
}

✅ 编译验证通过

3. 派生宏

#[derive(Debug, Clone, PartialEq)]
struct Person { name: String, age: u32 }

fn main() {
    let p1 = Person { name: String::from("Alice"), age: 30 };
    let p2 = p1.clone();
    println!("{:?}", p1);
    println!("相等: {}", p1 == p2);
}

✅ 编译验证通过

派生宏功能
Debug{:?}格式化
Clone深拷贝.clone()
Copy赋值自动复制
PartialEq== !=
Eq完全相等
HashHashMap键
Default默认值

4. 泛型结构体

struct Stack<T> {
    items: Vec<T>,
}

impl<T> Stack<T> {
    fn new() -> Self { Stack { items: Vec::new() } }
    fn push(&mut self, item: T) { self.items.push(item); }
    fn pop(&mut self) -> Option<T> { self.items.pop() }
    fn peek(&self) -> Option<&T> { self.items.last() }
    fn is_empty(&self) -> bool { self.items.is_empty() }
    fn size(&self) -> usize { self.items.len() }
}

fn main() {
    let mut s: Stack<i32> = Stack::new();
    s.push(1); s.push(2); s.push(3);
    while let Some(v) = s.pop() {
        println!("弹出: {}", v);
    }
}

✅ 编译验证通过

5. Builder模式

#[derive(Debug)]
struct Server {
    host: String,
    port: u16,
    tls: bool,
    timeout: u64,
}

struct ServerBuilder {
    host: String,
    port: u16,
    tls: bool,
    timeout: u64,
}

impl ServerBuilder {
    fn new(host: &str) -> Self {
        ServerBuilder { host: host.to_string(), port: 80, tls: false, timeout: 30 }
    }
    fn port(mut self, port: u16) -> Self { self.port = port; self }
    fn tls(mut self) -> Self { self.tls = true; self }
    fn timeout(mut self, t: u64) -> Self { self.timeout = t; self }
    fn build(self) -> Server {
        Server { host: self.host, port: self.port, tls: self.tls, timeout: self.timeout }
    }
}

fn main() {
    let server = ServerBuilder::new("localhost")
        .port(443)
        .tls()
        .timeout(60)
        .build();
    println!("{:?}", server);
}

✅ 编译验证通过

6. 内存布局

struct Rectangle { width: f64, height: f64 } 栈上:16 bytes,无padding ┌──────────────────┐ │ width: 10.0 │ 8 bytes ├──────────────────┤ │ height: 20.0 │ 8 bytes └──────────────────┘ struct User { name: String, email: String, age: u32, active: bool } ┌──────────────────┐ │ name: ptr+len+cap│ → 堆上"Alice" ├──────────────────┤ │ email: ptr+len+cap│ → 堆上"alice@ex.com" ├──────────────────┤ │ age: 30 │ 4 bytes │ active: true │ 1 byte + 3 padding └──────────────────┘ ⚠️ 字段顺序影响padding! struct A { a: u8, b: u64, c: u8 } // 24 bytes (padding) struct B { a: u8, c: u8, b: u64 } // 16 bytes (优化)

📝 练习题

练习1:实现LinkedList

用枚举和Box实现一个简单的链表。

练习2:内存优化

重排以下结构体字段以最小化padding。

练习3:newtype模式

用元组结构体实现类型安全的ID。

🏆

成就解锁:建造者

掌握结构体与方法——构建复杂数据类型的基础