Rust 结构体

三种结构体、方法、关联函数、以及 `#[derive]` 能给你什么。

Beginner
Key Points字段和方法分开定义:`struct` 写数据,`impl` 写行为。

三种形态

Rust
// 1. 具名字段
struct User {
    name: String,
    age: u32,
    active: bool,
}

// 2. 元组结构体
struct Point(i32, i32);

// 3. 单元结构体(无字段,常用于实现 trait)
struct Marker;

fn main() {
    let u = User { name: String::from("张三"), age: 28, active: true };
    let p = Point(3, 4);

    println!("{} {} {}", u.name, u.age, u.active);
    println!("{} {}", p.0, p.1);
    println!("{:?}", Marker);
}
Output
张三 28 true
3 4
Marker

方法与关联函数

Rust
struct Rect {
    w: f64,
    h: f64,
}

impl Rect {
    // 关联函数:没有 self,用 :: 调用
    fn new(w: f64, h: f64) -> Self {
        Rect { w, h }
    }

    fn square(size: f64) -> Self {
        Rect { w: size, h: size }
    }

    // 方法:&self 借用
    fn area(&self) -> f64 {
        self.w * self.h
    }

    // &mut self:能改字段
    fn scale(&mut self, factor: f64) {
        self.w *= factor;
        self.h *= factor;
    }

    // self:消费掉自己
    fn into_tuple(self) -> (f64, f64) {
        (self.w, self.h)
    }
}

fn main() {
    let mut r = Rect::new(3.0, 4.0);
    println!("{}", r.area());

    r.scale(2.0);
    println!("{}", r.area());

    let s = Rect::square(5.0);
    println!("{}", s.area());

    let t = r.into_tuple();
    println!("{:?}", t);
}
Output
12
48
25
(6.0, 8.0)
ReceiverMeaningUse
&self不可变借用只读方法
&mut self可变借用修改状态
self取得所有权转换、消耗
(无 self)关联函数构造函数、工具函数

derive

Rust
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct User {
    name: String,
    age: u32,
}

fn main() {
    let a = User { name: "张三".into(), age: 28 };
    let b = a.clone();

    println!("{:?}", a);
    println!("{}", a == b);

    let mut set = std::collections::HashSet::new();
    set.insert(a);
    println!("{}", set.len());
}
Output
User { name: "张三", age: 28 }
true
1
DeriveGives
Debug{:?} 打印
Clone.clone()
Copy赋值时复制而非移动
PartialEq / Eq== / !=
PartialOrd / Ord< > 与排序
Hash能当 HashMap 的键
DefaultDefault::default()
Copy requires every field to be Copy. String and Vec are not, so structs containing them can only Clone.

字段初始化简写与更新语法

Rust
#[derive(Debug, Clone)]
struct User {
    name: String,
    age: u32,
    active: bool,
}

fn main() {
    let name = String::from("李四");
    // 简写:字段名和变量名相同时只写一个
    let u1 = User { name, age: 30, active: true };

    // 更新语法:其余字段从另一个实例拿
    let u2 = User { age: 31, ..u1.clone() };
    println!("{:?}", u2);
}
Output
User { name: "李四", age: 31, active: true }

元组结构体的用处

Rust
// 给相同底层类型加类型安全
struct Meters(f64);
struct Feet(f64);

fn walk(d: Meters) -> String {
    format!("走了 {} 米", d.0)
}

fn main() {
    println!("{}", walk(Meters(100.0)));
    // walk(Feet(100.0));   // 编译错误:类型不匹配

    // 也常用于包装,实现外部 trait
    struct Wrapper(Vec<String>);
    let w = Wrapper(vec!["a".into()]);
    println!("{}", w.0.len());
}
Output
走了 100 米
1

This is the "newtype pattern". It is zero-cost (compiles to the inner f64) yet prevents passing feet where metres are expected. Wrapping and Saturating in std use it.

Friends & Partners