Rust 作為一種系統(tǒng)級(jí)編程語(yǔ)言, 與C/C++語(yǔ)言一樣,它們都有非常高效的內(nèi)存讀寫操作,因此三者都非常適合資源有限的嵌入式平臺(tái)的開發(fā)。 在很多編程語(yǔ)言中都有結(jié)構(gòu)體這個(gè)概念,常常用于面向?qū)ο箝_發(fā), 提高代碼內(nèi)聚, 降低耦合。Rust的結(jié)構(gòu)體與C的結(jié)構(gòu)體有非常多的相似之處,甚至可以使用#[repor(C)]
屬性, 直接與C/C++的結(jié)構(gòu)體進(jìn)行互操作。讓 Rust 調(diào)用 C 庫(kù)使用方法和 C
與 C++
代碼互相調(diào)用一樣簡(jiǎn)單。但 Rust 的結(jié)構(gòu)題體與 C 的結(jié)構(gòu)體也有非常多的不同之處,有更多的特性,用于簡(jiǎn)化編程,簡(jiǎn)化抽象邏輯。
定義方法
Rust 結(jié)構(gòu)體的預(yù)定義關(guān)鍵字與 C
一樣,都使用 struct
關(guān)鍵字開頭。但Rust 定義的后面通常無(wú)需添加分號(hào);
,除非結(jié)構(gòu)體為空。各子屬性的后面使用逗號(hào)分隔。 Rust 的結(jié)構(gòu)體定義方法如下
struct Point {
x: i32,
y: i32,
}
// 空結(jié)構(gòu)體定義方法
struct EmptyStruct;
構(gòu)造與初始化
Rust 的結(jié)構(gòu)體沒有要求必須有構(gòu)造函數(shù),但可以通過(guò)關(guān)聯(lián)函數(shù)(如 new)初始化:
#[derive(Default)]
struct Point {
x: i32,
y: i32,
}
impl Point {
pubfn new(x: i32, y: i32) -> Point {
Point { x, y } // 等價(jià)于 Point { x: x, y: y }
}
pubfn Point(point: Point) -> Point {
Point {
x: point.x,
..point // 等價(jià)于 Point { x: point.x, y: point.y }
}
}
}
需要注意的是,Rust 的字段必須都初始化后才能使用,否則編譯會(huì)報(bào)錯(cuò),來(lái)保證字段的安全性??墒褂?nbsp;#[derive(Default)]
注解來(lái)為結(jié)構(gòu)體添加默認(rèn)值。
內(nèi)部字段的訪問(wèn)
Rust 的結(jié)構(gòu)體的內(nèi)部字段可使用可見性修飾符,用于控制字段的訪問(wèn)權(quán)限。Rust 的結(jié)構(gòu)體支持以下可見性修飾符:
: 默認(rèn)可見性,字段只能在當(dāng)前模塊內(nèi)訪問(wèn)。
pub
:公共可見性,字段可以被外部訪問(wèn)。pub(crate)
:當(dāng)前 crate 內(nèi)可見,字段可以被當(dāng)前 crate 內(nèi)的代碼訪問(wèn)。pub(super)
:父級(jí)模塊可見,字段可以被父級(jí)模塊內(nèi)的代碼訪問(wèn)。
內(nèi)存排列
Rust 的結(jié)構(gòu)體的內(nèi)存排列與 C
結(jié)構(gòu)體的內(nèi)存排列不同。Rust 的結(jié)構(gòu)體的內(nèi)存排列是按照字段的定義順序進(jìn)行排列的,而 C
結(jié)構(gòu)體的內(nèi)存排列是按照字段的聲明順序進(jìn)行排列的。 Rust 的結(jié)構(gòu)體的內(nèi)存排列如下:
struct Display {
x: i32,
width: u8,
y: i32,
height: u8,
}
以上代碼在編譯后的內(nèi)存順序可能自動(dòng)調(diào)整為:
struct Display {
x: i32, // offset 0, size 4
y: i32, // offset 4, size 4
width: u8, // offset 8, size 1
height: u8, // offset 9, size 1
}
如果需要保持字段的內(nèi)存順序與C語(yǔ)言一致,可以使用#[repr(C)]
屬性,這樣就可以保持字段的內(nèi)存順序與C語(yǔ)言一致, 在與C交互時(shí)則會(huì)完全兼容。 如下:
#[repr(C)]
struct Display {
x: i32, // offset 0, size 4
width: u8, // offset 4, size 1
y: i32, // offset 8, size 4
height: u8, // offset 12, size 1
}
方法
Rust 的支持為結(jié)構(gòu)體定義方法,方法與函數(shù)的定義類似,只是方法定義在結(jié)構(gòu)體的內(nèi)部。方法的定義格式如下:
struct Point {
x: i32,
y: i32,
}
impl Point {
fn distance(&self, other: &Point) -> f64 {
let dx = self.x - other.x;
let dy = self.y - other.y;
(dx * dx + dy * dy) asf64
}
pubfn new(x: i32, y: i32) -> Point {
Point { x, y }
}
pub(crate) fn get_x(&self) -> i32 {
self.x
}
pub(super) fn get_y(&self) -> i32 {
self.y
}
}
如上所示,使用 impl
關(guān)鍵字定義結(jié)構(gòu)體的方法,
- 內(nèi)部的第一個(gè)參數(shù)如果為
self
,表示當(dāng)前結(jié)構(gòu)體的實(shí)例中可使用, 當(dāng)所有權(quán)會(huì)被移動(dòng)。 - 如果方法的第一個(gè)參數(shù)的類型為
&self
,表示當(dāng)前結(jié)構(gòu)體的實(shí)例的引用,結(jié)構(gòu)體變量所有權(quán)不會(huì)移動(dòng),無(wú)法修改內(nèi)部屬性的值。 - 方法的第一個(gè)參數(shù)的類型為
&mut self
,表示當(dāng)前結(jié)構(gòu)體的實(shí)例的可變引用,當(dāng)前函數(shù)可修改內(nèi)部屬性的值。 - 如果函數(shù)的第一個(gè)參數(shù)非
self
、&self
、&mut self
,則表示當(dāng)前函數(shù)為靜態(tài)方法, 可直接通過(guò)結(jié)構(gòu)體名調(diào)用。
Rust 也能使用 impl trait_name for struct_name
來(lái)為結(jié)構(gòu)體實(shí)現(xiàn) trait, 如下:
struct Point {
x: i32,
y: i32,
}
impl Display for Point {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "({},{})", self.x, self.y)
}
}
以上代碼定義了一個(gè) Point
結(jié)構(gòu)體,并為其實(shí)現(xiàn)了 Display
trait, 這樣就可以使用 println!
宏來(lái)打印 Point
結(jié)構(gòu)體的實(shí)例。
let p = Point { x: 1, y: 2 };
// 代碼會(huì)輸出 `(1,2)`。
println!("{}", p);
所有權(quán)與生命周期
Rust 的結(jié)構(gòu)體可以包含引用(&T 或 &mut T),但必須指定生命周期:
struct Bar<'a> {
data: &'a str, // 必須標(biāo)注生命周期
}
范型化
Rust 的結(jié)構(gòu)體支持模板化, 可以使用泛型來(lái)定義結(jié)構(gòu)體, 如下:
struct Point {
x: T,
y: T,
}
以上代碼定義了一個(gè) Point
結(jié)構(gòu)體, 其中 x
和 y
都是泛型類型 T
, 可以是任意類型。這樣就可以使用 Point
結(jié)構(gòu)體來(lái)表示任意類型的點(diǎn), 適應(yīng)不同的場(chǎng)景。
let p = Point { x: 1, y: 2 };
let p = Point { x: 1.0, y: 2.0 };
模式匹配
Rust 的結(jié)構(gòu)體支持模式匹配, 可以使用模式匹配來(lái)解構(gòu)結(jié)構(gòu)體, 如下:
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 1, y: 2 };
match p {
Point { x, y } => println!("x={}, y={}", x, y),
_ => println!("other"),
}
}
以上代碼定義了一個(gè) Point
結(jié)構(gòu)體, 并在 main
函數(shù)中使用模式匹配來(lái)解構(gòu) Point
結(jié)構(gòu)體的實(shí)例, 解構(gòu)后可以使用 x
和 y
變量來(lái)訪問(wèn)結(jié)構(gòu)體的內(nèi)部屬性。
析構(gòu)函數(shù)
Rust 的結(jié)構(gòu)體都有析構(gòu)函數(shù), 析構(gòu)函數(shù)在結(jié)構(gòu)體被釋放時(shí)自動(dòng)調(diào)用, 可以用于釋放資源, 如下:
struct Foo {
data: Vec,
}
impl Drop for Foo {
fn drop(&mut self) {
println!("Foo is dropped");
}
}
結(jié)構(gòu)體變量在釋放時(shí)默認(rèn)會(huì)為內(nèi)部的字段執(zhí)行析構(gòu)函數(shù),避免內(nèi)存泄漏,保證內(nèi)存安全。
總結(jié)
Rust 的結(jié)構(gòu)體與 C 的結(jié)構(gòu)體有非常多的不同之處, 但 Rust 的結(jié)構(gòu)體也有非常多的優(yōu)點(diǎn),用于提高內(nèi)存安全和簡(jiǎn)化編程, 如:
- 支持范型化, 可以使用泛型來(lái)定義不同屬性類型的結(jié)構(gòu)體
- 支持模式匹配, 可以使用模式匹配來(lái)解構(gòu)結(jié)構(gòu)體
- 支持析構(gòu)函數(shù), 可以使用析構(gòu)函數(shù)來(lái)釋放資源
- 支持生命周期, 可以使用生命周期來(lái)指定結(jié)構(gòu)體的引用的生命周期
- 支持引用, 可以使用引用來(lái)指向結(jié)構(gòu)體的內(nèi)部屬性
- 支持方法, 可以使用方法來(lái)定義結(jié)構(gòu)體的行為
- 支持可見性修飾符, 可以使用可見性修飾符來(lái)控制字段的訪問(wèn)權(quán)限
- 支持內(nèi)存排列, 可以使用內(nèi)存排列來(lái)指定結(jié)構(gòu)體的內(nèi)存布局
- 支持構(gòu)造函數(shù), 可以使用構(gòu)造函數(shù)來(lái)初始化結(jié)構(gòu)體的實(shí)例
- 支持靜態(tài)方法, 可以使用靜態(tài)方法來(lái)定義結(jié)構(gòu)體的行為
- 支持兼容C, 可以使用
#[repr(C)]
屬性來(lái)與C語(yǔ)言交互, 適應(yīng)多語(yǔ)言編程