Rust 結(jié)構(gòu)體 (struct) 的詳細(xì)知識(shí)點(diǎn)
涵蓋:三類形式、實(shí)例化語法、內(nèi)存布局、方法 impl、派生 trait、遞歸結(jié)構(gòu)體等
特點(diǎn):結(jié)合棧/堆分配詳解,含高頻易錯(cuò)點(diǎn)總結(jié)
一、結(jié)構(gòu)體三類形式
Rust 有三種結(jié)構(gòu)體,用途完全不同:
1. 具名字段結(jié)構(gòu)體(最常用)
每個(gè)成員帶字段名,適合復(fù)雜業(yè)務(wù)數(shù)據(jù):
struct User {
name: String,
age: u32,
is_vip: bool,
}
// 實(shí)例化
let u = User {
name: "張三".to_string(),
age: 22,
is_vip: false,
};
// 訪問/修改(必須 mut 實(shí)例)
println!("{}", u.name);
let mut u2 = User { name: "李四".into(), age: 30, is_vip: true };
u2.age = 31;
2. 元組結(jié)構(gòu)體(無字段名,只用下標(biāo)訪問)
適合簡單包裝、FFI、newtype 模式:
struct Point(i32, i32);
struct Color(u8, u8, u8);
let p = Point(10, 20);
println!("{} {}", p.0, p.1);
3. 單元結(jié)構(gòu)體(無任何字段)
僅用作標(biāo)記、trait 實(shí)現(xiàn)標(biāo)記類型:
struct EmptyFlag; let flag = EmptyFlag;
二、實(shí)例化簡寫語法
1. 字段簡寫(變量名和字段同名)
fn build_user(name: String, age: u32) -> User {
User {
name, // 等價(jià) name: name
age,
is_vip: false,
}
}
2. 結(jié)構(gòu)體更新語法..復(fù)用舊實(shí)例
只修改部分字段,其余繼承原有值:
let u1 = User { name: "A".into(), age: 18, is_vip: false };
let u2 = User { age: 20, ..u1 };
// u2.name = "A", u2.is_vip = false,僅 age 改為 20
?? 所有權(quán)注意:..u1 會(huì)轉(zhuǎn)移 u1 內(nèi)堆類型字段所有權(quán)(String/Vec),之后不能再使用 u1。
三、內(nèi)存布局 & 棧/堆分配(重點(diǎn))
1. 純值結(jié)構(gòu)體(無任何堆類型字段)
所有成員都是 i32/f64/bool/[T;N] 等值類型:整個(gè)結(jié)構(gòu)體完整平鋪在棧,內(nèi)部無指針,無堆內(nèi)存。
struct Point { x: i32, y: f64 }
let p = Point {x:1, y:2.0}; // 全部棧
2. 結(jié)構(gòu)體包含堆容器字段(String/Vec/Box/Arc 等)
結(jié)構(gòu)體實(shí)例本體依然在棧;只是對(duì)應(yīng)字段內(nèi)部存儲(chǔ)指針,真實(shí)數(shù)據(jù)存堆。
struct Student {
id: u64,
name: String, // String 棧存三元指針,字符堆
scores: Vec<u8> // Vec 棧存指針數(shù)組,元素堆
}
let s = Student { ... };
// s 整體在棧;name、scores 的真實(shí)數(shù)據(jù)在堆
3. 結(jié)構(gòu)體整體放到堆上
外層套 Box/Rc/Arc/Mutex,棧只存一根指針,結(jié)構(gòu)體本體全部堆分配:
let heap_point: Box<Point> = Box::new(Point{x:0, y:0});
// heap_point 變量棧;Point 結(jié)構(gòu)體存在堆
4. 內(nèi)存對(duì)齊與布局
| 情況 | 說明 |
|---|---|
| 默認(rèn) | Rust 不保證字段順序、對(duì)齊和 C 一致,編譯器會(huì)重排優(yōu)化內(nèi)存 |
| #[repr(C)] | 如需和 C 交互固定布局,加此屬性 |
#[repr(C)]
struct CPoint {
x: i32,
y: i32,
}
四、結(jié)構(gòu)體方法 impl
1. 關(guān)聯(lián)函數(shù)(無 &self,類似構(gòu)造器)
調(diào)用方式:Type::func(),常命名為 new()
impl User {
// 構(gòu)造器,關(guān)聯(lián)函數(shù)
fn new(name: &str, age: u32) -> Self {
Self {
name: name.to_string(),
age,
is_vip: false,
}
}
}
let u = User::new("老王", 25);
2. 實(shí)例方法(帶 &self / &mut self / self)
| 參數(shù)類型 | 含義 |
|---|---|
| &self | 只讀借用,不修改結(jié)構(gòu)體 |
| &mut self | 可變借用,修改內(nèi)部字段 |
| self | 獲取所有權(quán),調(diào)用后原實(shí)例失效 |
impl User {
// 只讀方法
fn get_age(&self) -> u32 {
self.age
}
// 修改自身
fn become_vip(&mut self) {
self.is_vip = true;
}
// 拿走所有權(quán)
fn consume(self) {
println!("{}", self.name);
}
}
3. 關(guān)聯(lián)常量
impl User {
const MAX_AGE: u32 = 150;
}
println!("{}", User::MAX_AGE);
五、所有權(quán)與解構(gòu)
1. 解構(gòu)賦值
let User { name, age, is_vip } = u;
// name 拿到 String 所有權(quán),u 失效
只想借用不轉(zhuǎn)移所有權(quán):解構(gòu)引用
let User { ref name, .. } = &u;
// 等價(jià) let name = &u.name;
2. 字段借用規(guī)則
let mut u = User::new("test", 20);
let a = &u.name; // 不可變借用
let b = &mut u.age; // 可變借用
// 同一字段不能同時(shí)存在可變 + 不可變借用;不同字段允許
六、派生 trait(derive 常用)
給結(jié)構(gòu)體自動(dòng)實(shí)現(xiàn)標(biāo)準(zhǔn)功能,開發(fā)高頻:
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Point { x: i32, y: i32 }
| Trait | 功能 |
|---|---|
| Debug | 支持 println!("{:?}", p) 打印調(diào)試信息 |
| Clone | .clone() 深拷貝實(shí)例 |
| Copy | 值可棧拷貝,要求所有字段都實(shí)現(xiàn) Copy(不能含 String/Vec) |
| PartialEq / Eq | 支持 == 相等比較 |
| Hash | 可作為 HashMap key |
| Default | User::default() 快速生成默認(rèn)值 |
Copy 關(guān)鍵限制:包含 String、Vec、Box 堆類型的結(jié)構(gòu)體無法 derive Copy,只能 Clone。
七、嵌套結(jié)構(gòu)體
結(jié)構(gòu)體字段可以是另一個(gè)結(jié)構(gòu)體:
struct Address {
city: String,
street: String,
}
struct User {
name: String,
addr: Address, // 嵌套結(jié)構(gòu)體
}
// 訪問
user.addr.city
八、遞歸結(jié)構(gòu)體(自身包含自己)
直接嵌套會(huì)無限尺寸編譯報(bào)錯(cuò),必須用 Box 把自身放堆:
// 報(bào)錯(cuò):無限大小
struct Node {
next: Node
}
// 正確,Box 棧存指針,子節(jié)點(diǎn)堆分配
struct Node {
val: i32,
next: Option<Box<Node>>
}
九、結(jié)構(gòu)體 vs 元組 vs 枚舉 核心區(qū)分
| 類型 | 特點(diǎn) |
|---|---|
| struct | 同時(shí)擁有所有字段,描述單一事物完整屬性;可命名字段可讀性強(qiáng) |
| tuple | 固定長度、可多類型、無字段名,輕量臨時(shí)組合 |
| enum | 同一時(shí)間僅存一種變體,互斥多種形態(tài) |
十、高頻易錯(cuò)點(diǎn)總結(jié)
?? 以下易錯(cuò)點(diǎn)需特別注意
- 修改字段必須實(shí)例聲明 mut,只標(biāo)記字段 mut 無效
- 結(jié)構(gòu)體更新語法 ..s 會(huì)轉(zhuǎn)移堆字段所有權(quán),原變量失效
- 含 String/Vec 的結(jié)構(gòu)體不能 derive Copy,只能 Clone
- 遞歸結(jié)構(gòu)體內(nèi)部自引用必須包 Box,否則編譯無限尺寸
- 無 #[repr(C)] 時(shí)內(nèi)存字段順序不固定,不能直接和 C 結(jié)構(gòu)體對(duì)等
- 結(jié)構(gòu)體本體默認(rèn)棧分配;僅外層套 Box/Arc 時(shí)整體進(jìn)堆
- 解構(gòu)堆類型結(jié)構(gòu)體默認(rèn)轉(zhuǎn)移所有權(quán),想要借用需要匹配引用 &self
十一、速記口訣
結(jié)構(gòu)三分具名元組單元,new 構(gòu)造 impl 加方法;
點(diǎn)號(hào)訪問可 mut 修改,..語法快速復(fù)用舊實(shí)例;
純值字段全存棧,字符串 vec 堆上藏;
遞歸嵌套包 Box,derive 派生 Debug 克隆相等;
C 交互加 repr(C),Copy 僅限純棧值類型。
到此這篇關(guān)于Rust 結(jié)構(gòu)體 (struct) 的詳細(xì)知識(shí)點(diǎn)的文章就介紹到這了,更多相關(guān)Rust 結(jié)構(gòu)體內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
rust中間件actix_web在項(xiàng)目中的使用實(shí)戰(zhàn)
這篇文章主要介紹了rust中間件在項(xiàng)目中的使用實(shí)戰(zhàn),包括自定義中間件,日志中間件,Default?headers,用戶會(huì)話,錯(cuò)誤處理的用法實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01
Rust中FFI編程知識(shí)點(diǎn)整理總結(jié)(推薦)
這篇文章主要介紹了Rust中FFI編程知識(shí)點(diǎn)整理總結(jié),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-09-09
Rust?實(shí)現(xiàn)?async/await的詳細(xì)代碼
異步編程在 Rust 中的地位非常高,很多 crate 尤其是多IO操作的都使用了 async/await,這篇文章主要介紹了Rust?如何實(shí)現(xiàn)?async/await,需要的朋友可以參考下2022-09-09
rust 如何使用 cargo-nextest 替代 cargo te
cargo-nextest 是新一代的rust測試程序,能夠極大提升測試性能,可以完全替代 cargo test 命令,這篇文章主要介紹了rust 如何使用 cargo-nextest 替代 cargo test,需要的朋友可以參考下2024-05-05
Rust 中單線程 Web 服務(wù)器的實(shí)現(xiàn)
本文用Rust構(gòu)建單線程Web服務(wù)器,通過HTTP/TCP處理請(qǐng)求,返回hello.html或404.html,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-06-06

