Rust 结构体
三种结构体、方法、关联函数、以及 `#[derive]` 能给你什么。
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)| Receiver | Meaning | Use |
|---|---|---|
&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| Derive | Gives |
|---|---|
Debug | {:?} 打印 |
Clone | .clone() |
Copy | 赋值时复制而非移动 |
PartialEq / Eq | == / != |
PartialOrd / Ord | < > 与排序 |
Hash | 能当 HashMap 的键 |
Default | Default::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 米
1This 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.
三种形态
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)| 接收者 | 含义 | 适用 |
|---|---|---|
&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| 派生 | 提供 |
|---|---|
Debug | {:?} 打印 |
Clone | .clone() |
Copy | 赋值时复制而非移动 |
PartialEq / Eq | == / != |
PartialOrd / Ord | < > 与排序 |
Hash | 能当 HashMap 的键 |
Default | Default::default() |
Copy 只能给所有字段都是 Copy 的类型。String、Vec 不是 Copy,所以含它们的结构体不能 derive Copy,只能 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这种写法叫「newtype 模式」。它零成本(编译后就是内部的 f64),但能挡住「把英尺当米传」这类错误。标准库里 Wrapping、Saturating 都是这个套路。