Rust數(shù)據(jù)類(lèi)型之結(jié)構(gòu)體Struct的使用
結(jié)構(gòu)體(Struct)
是一種自定義數(shù)據(jù)類(lèi)型,允許將多個(gè)相關(guān)的值組合在一起,形成一個(gè)更復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。結(jié)構(gòu)體被廣泛應(yīng)用于組織和管理數(shù)據(jù),具有靈活性和強(qiáng)大的表達(dá)能力。
定義與聲明
結(jié)構(gòu)體定義
在Rust中,定義和聲明結(jié)構(gòu)體的語(yǔ)法如下:
struct Name {
field1: Type1,
field2: Type2,
// ...
fieldN: TypeN,
}其中,Name是結(jié)構(gòu)體的名稱(chēng),每個(gè)數(shù)據(jù)名及其對(duì)應(yīng)的數(shù)據(jù)類(lèi)型組成一個(gè)字段,field1到fieldN是結(jié)構(gòu)體的字段名稱(chēng),Type1到TypeN是字段的數(shù)據(jù)類(lèi)型。
通過(guò)關(guān)鍵字 struct 定義,指定結(jié)構(gòu)體名稱(chēng),結(jié)構(gòu)體內(nèi)用 field:type, 表示字段名稱(chēng)及數(shù)據(jù)類(lèi)型,注意rust語(yǔ)言不能在定義的同時(shí)進(jìn)行賦值,且用逗號(hào)分隔各字段,不像c/c++用分號(hào)。
結(jié)構(gòu)體中可以根據(jù)需要定義字段個(gè)數(shù),理論上要多少就定義多少;但實(shí)際上字段太多,結(jié)構(gòu)體也會(huì)變得很占空間,對(duì)程序的空間效率是個(gè)負(fù)擔(dān)。
結(jié)構(gòu)體實(shí)例
如以下代碼定義了一個(gè)名為Point的結(jié)構(gòu)體,包含x和y兩個(gè)字段,類(lèi)型分別為i32和f64:
struct Point {
x: i32,
y: f64,
}定義結(jié)構(gòu)體后,可以像使用其他類(lèi)型一樣使用它。例如,可以聲明一個(gè)Point類(lèi)型的變量,并為其字段賦值:
let my_point = Point { x: 10, y: 20.0 };使用結(jié)構(gòu)體時(shí),用成員運(yùn)算符 my_point.x 來(lái)調(diào)用對(duì)應(yīng)字段的值:
println!("({},{})", point.x, point.y); // 輸出:(10,20)可變實(shí)例
需要變動(dòng)字段的值,在聲明時(shí)需要用 let mut,如:
struct Point {
x: i32,
y: f64,
}
fn main() {
let mut point = Point { x: 10, y: 20.0 };
point.x = 5;
println!("({},{})", point.x, point.y); // 輸出:(5,20)
}結(jié)構(gòu)體分類(lèi)
在Rust中,結(jié)構(gòu)體(Struct)可以按照不同的方式進(jìn)行分類(lèi),以下是一些常見(jiàn)的分類(lèi)方式:
單元結(jié)構(gòu)體(Unit Struct)
這種結(jié)構(gòu)體沒(méi)有任何字段,它只是用于表示一個(gè)空的類(lèi)型。這種結(jié)構(gòu)體通常用于作為其他結(jié)構(gòu)體的組成部分或返回類(lèi)型。例如:
struct UnitStruct;
元組結(jié)構(gòu)體(Tuple Struct)
這種結(jié)構(gòu)體包含一組字段,可以通過(guò)元組語(yǔ)法來(lái)訪問(wèn)每個(gè)字段。元組結(jié)構(gòu)體可以用于表示簡(jiǎn)單的數(shù)據(jù)集合,不使用大括號(hào){},而是使用元組的小括號(hào)()。例如:
struct TupleStruct(i32, String);
相當(dāng)字段數(shù)據(jù)沒(méi)有名稱(chēng)的結(jié)構(gòu)體,訪問(wèn)時(shí)使用索引。如:
struct Point (i32, f64);
fn main() {
let mut point = Point(10, 20.0);
point.0 = 5;
println!("({},{})", point.0, point.1);
}具名結(jié)構(gòu)體(Named Struct)
這種結(jié)構(gòu)體有一個(gè)顯式的名稱(chēng),并且包含一組字段。具名結(jié)構(gòu)體可以用于表示復(fù)雜的數(shù)據(jù)結(jié)構(gòu),例如一個(gè)包含多個(gè)字段的對(duì)象,本文的示例大多數(shù)都為具名結(jié)構(gòu)體,用法已在本文開(kāi)頭講過(guò):
struct MyStruct {
field1: i32,
field2: String,
// ...
}除了以上三種常見(jiàn)的結(jié)構(gòu)體類(lèi)型,Rust還支持其他特殊類(lèi)型的結(jié)構(gòu)體,例如帶有泛型參數(shù)的結(jié)構(gòu)體、具名元組結(jié)構(gòu)體(Named Tuple Struct)和結(jié)構(gòu)體路徑(Struct Type Alias)等。
需要注意的是,在Rust中,結(jié)構(gòu)體的分類(lèi)并不是強(qiáng)制性的,也就是說(shuō),一個(gè)結(jié)構(gòu)體可以包含任意類(lèi)型的字段,并且可以在任何地方使用。這使得結(jié)構(gòu)體非常靈活,可以用于實(shí)現(xiàn)各種復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。
結(jié)構(gòu)體字段的數(shù)據(jù)類(lèi)型可以是以下常見(jiàn)的rust數(shù)據(jù),甚至可以是函數(shù)、引用、指針類(lèi)型。
標(biāo)量類(lèi)型(Scalar Types):
- 整數(shù)類(lèi)型(Integer Types):包括有符號(hào)整數(shù)類(lèi)型和無(wú)符號(hào)整數(shù)類(lèi)型。常見(jiàn)的整數(shù)類(lèi)型有
i8、i16、i32、i64、i128表示有符號(hào)整數(shù),u8、u16、u32、u64、u128表示無(wú)符號(hào)整數(shù)。此外,還有isize和usize,它們根據(jù)平臺(tái)的位數(shù)自動(dòng)調(diào)整大小。 - 浮點(diǎn)數(shù)類(lèi)型(Floating-Point Number Types):包括
f32和f64兩種類(lèi)型,表示單精度和雙精度浮點(diǎn)數(shù)。 - 布爾類(lèi)型(Boolean Type):只有兩個(gè)取值,
true和false。 - 字符類(lèi)型(Character Type):表示單個(gè) Unicode 字符,通常存儲(chǔ)為 4 個(gè)字節(jié)。
- 整數(shù)類(lèi)型(Integer Types):包括有符號(hào)整數(shù)類(lèi)型和無(wú)符號(hào)整數(shù)類(lèi)型。常見(jiàn)的整數(shù)類(lèi)型有
復(fù)合類(lèi)型(Composite Types):
- 數(shù)組類(lèi)型(Array Types):由相同類(lèi)型的元素組成的有限集合??梢酝ㄟ^(guò)固定長(zhǎng)度或動(dòng)態(tài)長(zhǎng)度來(lái)定義數(shù)組。
- 切片類(lèi)型(Slice Types):對(duì)一個(gè)連續(xù)的內(nèi)存塊進(jìn)行引用,可以看作是動(dòng)態(tài)數(shù)組。切片類(lèi)型提供了訪問(wèn)和操作數(shù)據(jù)的一種高效方式。
- 元組類(lèi)型(Tuple Types):一種將多個(gè)不同類(lèi)型的值組合在一起的數(shù)據(jù)結(jié)構(gòu),用圓括號(hào)和逗號(hào)分隔的元素序列表示。元組可以包含不同類(lèi)型的元素,例如整數(shù)、浮點(diǎn)數(shù)、布爾值、字符串等。
- 結(jié)構(gòu)體類(lèi)型(Struct Types):一種自定義的數(shù)據(jù)類(lèi)型,可以包含多個(gè)不同類(lèi)型的字段。結(jié)構(gòu)體可以通過(guò)定義來(lái)指定其字段和屬性。
- 枚舉類(lèi)型(Enum Types):表示一個(gè)可能取多個(gè)值的變量。在 Rust 中,枚舉類(lèi)型使用
enum關(guān)鍵字定義,每個(gè)可能的取值都是一個(gè)不同的枚舉成員。
結(jié)構(gòu)體嵌套
一個(gè)結(jié)構(gòu)體可以包含任意類(lèi)型的字段,當(dāng)然也包括結(jié)構(gòu)體。
在以下這個(gè)例子中,Address 結(jié)構(gòu)體包含了 street、city 和 state 三個(gè)字段,而 Person 結(jié)構(gòu)體則包含了 name、age 和 address 三個(gè)字段,其中 address 字段的類(lèi)型是 Address 結(jié)構(gòu)體。
struct Address {
street: String,
city: String,
state: String,
}
struct Person {
name: String,
age: u8,
address: Address,
}結(jié)構(gòu)體方法
方法(method)是在結(jié)構(gòu)體上定義的功能,可以訪問(wèn)結(jié)構(gòu)體的字段并執(zhí)行一些操作。使用關(guān)鍵字impl,結(jié)構(gòu)體可以對(duì)應(yīng)一個(gè)或多個(gè)impl代碼塊。
例1:結(jié)構(gòu)體轉(zhuǎn)換為字符串描述
struct Student {
name:String,
age:u32,
school:String,
major:String,
grade:String,
state:bool
}
impl Student {
fn to_string(&self) -> String {
format!("Student {{ name: {}, age: {}, school: {}, major: {}, grade: {}, state: {} }}",
self.name, self.age, self.school, self.major, self.grade, self.state)
}
}
fn main() {
let school = String::from("東南大學(xué)");
let major = String::from("土木工程學(xué)院");
let s = Student{
name:String::from("楊程"),
age:22,
school,
major,
grade:String::from("大三"),
state:true
};
println!("{}", s.to_string());
}輸出:
Student { name: 楊程, age: 22, school: 東南大學(xué), major: 土木工程學(xué)院, grade: 大三, state: true }
注意:上例中有一個(gè)rust結(jié)構(gòu)體的特殊用法,使用同名變量在結(jié)構(gòu)體外為對(duì)應(yīng)字段賦值。
例2:矩形的周長(zhǎng)和面積
struct Rectangle {
width: f32,
height: f32,
}
impl Rectangle {
// 構(gòu)造函數(shù)
fn new(width: f32, height: f32) -> Rectangle {
Rectangle { width, height }
}
// 計(jì)算矩形的面積
fn area(&self) -> f32 {
self.width * self.height
}
// 計(jì)算矩形的周長(zhǎng)
fn perimeter(&self) -> f32 {
(self.width + self.height) * 2.0
}
}
impl Rectangle {
// 判斷矩形是否相等
fn is_equal(&self, other: &Rectangle) -> bool {
self.width == other.width && self.height == other.height
}
}
fn main() {
let rect1 = Rectangle::new(5.0, 6.0);
let rect2 = Rectangle::new(5.0, 6.0);
println!("Rectangle 1 area: {}", rect1.area());
println!("Rectangle 1 perimeter: {}", rect1.perimeter());
println!("Rectangle 2 area: {}", rect2.area());
println!("Rectangle 2 perimeter: {}", rect2.perimeter());
if rect1.is_equal(&rect2) {
println!("Rectangles are equal");
} else {
println!("Rectangles are not equal");
}
}輸出:
Rectangle 1 area: 30
Rectangle 1 perimeter: 22
Rectangle 2 area: 30
Rectangle 2 perimeter: 22
Rectangles are equal
例3:結(jié)構(gòu)體字段的更新與輸出
struct Person {
name: String,
age: u32,
}
impl Person {
// 這是構(gòu)造函數(shù),用于創(chuàng)建一個(gè)新的 Person 實(shí)例
fn new(name: String, age: u32) -> Person {
Person { name, age }
}
fn say_hello(&self) {
println!("Hello, my name is {} and I'm {}.", self.name, self.age);
}
fn update_age(&mut self, new_age: u32) {
self.age = new_age;
}
fn update_name(&mut self, new_name: String) {
self.name = new_name;
}
}
fn main() {
// 創(chuàng)建一個(gè)新的 Person 實(shí)例
let mut person = Person::new("Tom".to_string(), 5);
// 調(diào)用 say_hello 方法,輸出 Person 的信息
person.say_hello();
// 調(diào)用 update_age 方法,更新 Person 的年齡
person.update_age(3);
// 再次調(diào)用 say_hello 方法,輸出更新后的信息
person.say_hello();
person.update_age(5);
person.update_name(String::from("Jerry"));
person.say_hello();
}輸出:
Hello, my name is Tom and I'm 5.
Hello, my name is Tom and I'm 3.
Hello, my name is Jerry and I'm 5.
關(guān)聯(lián)函數(shù)
之所以"結(jié)構(gòu)體方法"不叫"結(jié)構(gòu)體函數(shù)"是因?yàn)?quot;函數(shù)"這個(gè)名字留給了這種函數(shù):它在 impl 塊中卻沒(méi)有 &self 參數(shù)。這種函數(shù)不依賴(lài)實(shí)例,但是使用它需要聲明是在哪個(gè) impl 塊中的,比如上小節(jié)例2和例3中的構(gòu)造函數(shù)new()就是關(guān)聯(lián)函數(shù),類(lèi)似于字符串函數(shù)String::new(),String::from("Jerry")。
示例:
#[derive(Debug,Clone)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn create(width: u32, height: u32) -> Rectangle {
Rectangle { width, height }
}
fn area(self) -> u32 {
self.width * self.height
}
fn area2(&self) -> u32 {
self.width * self.height
}
}
fn main() {
let rect = Rectangle::create(30, 50);
println!("{:?}", rect);
println!("Area: {}", Rectangle::area(rect.clone()));
println!("Area: {}", rect.area2());
}輸出:
Rectangle { width: 30, height: 50 }
Area: 1500
Area: 1500
結(jié)構(gòu)體方法與關(guān)聯(lián)函數(shù)的區(qū)別
參數(shù)傳遞方式的區(qū)別
結(jié)構(gòu)體方法:結(jié)構(gòu)體方法默認(rèn)情況下是可變的(mutable),也就是說(shuō)可以修改結(jié)構(gòu)體的字段。在調(diào)用方法時(shí),可以通過(guò)引用(&self)或可變引用(&mut self)來(lái)傳遞結(jié)構(gòu)體實(shí)例,以便修改其字段。例如:my_struct.my_method(&mut my_struct)。
關(guān)聯(lián)函數(shù):關(guān)聯(lián)函數(shù)默認(rèn)情況下是不可變的(immutable),也就是說(shuō)無(wú)法修改結(jié)構(gòu)體的字段。在調(diào)用函數(shù)時(shí),只能通過(guò)常量引用(&self)來(lái)傳遞結(jié)構(gòu)體實(shí)例,因?yàn)槌A恳檬侵蛔x的。例如:let my_struct = MyStruct {...}; my_struct.my_function()。
使用方式的區(qū)別
結(jié)構(gòu)體方法:結(jié)構(gòu)體方法可以直接在結(jié)構(gòu)體實(shí)例上調(diào)用,無(wú)需顯式傳遞結(jié)構(gòu)體實(shí)例。例如:my_struct.my_method()。
關(guān)聯(lián)函數(shù):關(guān)聯(lián)函數(shù)需要顯式傳遞結(jié)構(gòu)體實(shí)例作為參數(shù)。例如:MyStruct::my_function(my_struct)。
結(jié)構(gòu)體的trait
Rust 中的 trait 是一種抽象類(lèi)型,用于定義泛型行為,trait 可以理解為一種接口。trait 使用關(guān)鍵字 derive 來(lái)自動(dòng)生成實(shí)現(xiàn)。通過(guò)使用 derive,可以避免手動(dòng)編寫(xiě)冗長(zhǎng)的代碼,提高代碼的可讀性和可維護(hù)性。trait 有很多,比如Copy,Clone,Debug,Default,Drop,Hash,Ord,PartialOrd,Send,Sync等等,先挑幾種最常用的學(xué)一下:
#[derive(Debug)]
在 Rust 語(yǔ)言中用于自動(dòng)生成一個(gè)結(jié)構(gòu)體的 Debug 實(shí)現(xiàn),Debug 是 Rust 標(biāo)準(zhǔn)庫(kù)中的一個(gè) trait,用于在控制臺(tái)打印調(diào)試信息。
使用 #[derive(Debug)] 屬性可以為結(jié)構(gòu)體自動(dòng)生成一個(gè) Debug 實(shí)現(xiàn),這樣在需要打印調(diào)試信息時(shí),就可以使用 {:?} 格式化字符串來(lái)打印該結(jié)構(gòu)體的內(nèi)容。例如,在上面的代碼中,s 結(jié)構(gòu)體的 Debug 實(shí)現(xiàn)已經(jīng)被自動(dòng)生成,因此可以使用 println!("{:?}", s) 來(lái)打印出結(jié)構(gòu)體 s 的內(nèi)容。
例1:
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
impl Point {
fn distance(&self, other: &Point) -> f32 {
let x_diff = self.x - other.x;
let y_diff = self.y - other.y;
((x_diff * x_diff + y_diff * y_diff) as f32).sqrt()
}
}
fn main() {
let p1 = Point { x: 3, y: 0 };
let p2 = Point { x: 0, y: 4 };
println!("Distance between {:?} and {:?} is {}.", p1, p2, p1.distance(&p2));
}輸出:
Distance between Point { x: 3, y: 0 } and Point { x: 0, y: 4 } is 5.
例2:
#[derive(Debug)]
struct Student {
name: String,
age: u32,
school: String,
major: String,
grade: String,
state: bool,
}
impl Student {
fn new() -> Student {
return Student {
age: 0,
name: String::new(),
school: String::from(""),
major: "".to_string(),
grade: "".to_string(),
state: false,
};
}
}
fn main() {
let mut s = Student::new();
s.name = String::from("楊程");
s.age = 22;
s.school = String::from("東南大學(xué)");
s.major = String::from("土木工程學(xué)院");
s.grade = String::from("大三");
s.state = true;
println!("{:?}", s);
}輸出:
Student { name: "楊程", age: 22, school: "東南大學(xué)", major: "土木工程學(xué)院", grade: "大三", state: true }
與上一小節(jié)的例2對(duì)比,輸出內(nèi)容基本一致,就多了String的引號(hào)標(biāo)記。相比自動(dòng)生成 Debug 實(shí)現(xiàn)可以簡(jiǎn)化代碼編寫(xiě)過(guò)程,并且可以避免手動(dòng)實(shí)現(xiàn) Debug 時(shí)可能出現(xiàn)的錯(cuò)誤。
在本例中,使用宏打印結(jié)構(gòu)體println!("{:?}", s);時(shí),第一行的代碼#[derive(Debug)]是必須的,如果去掉就會(huì)報(bào)錯(cuò):
error[E0277]: `Student` doesn't implement `Debug`
--> E:\.rs\struct2.rs:31:22
|
31 | println!("{:?}", s);
| ^ `Student` cannot be formatted using `{:?}`
|
= help: the trait `Debug` is not implemented for `Student`
= note: add `#[derive(Debug)]` to `Student` or manually `impl Debug for Student`
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Student` with `#[derive(Debug)]`
|
1 + #[derive(Debug)]
2 | struct Student {
|error: aborting due to previous error
自定義打印宏
1. impl fmt::Debug for Student
返回值:fmt::Result; 調(diào)用:println!("{:?}", s);
use std::fmt;
struct Student {
name: String,
age: u32,
school: String,
major: String,
grade: String,
state: bool,
}
impl fmt::Debug for Student {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f,
"Student {{ name: {}, age: {}, school: {}, major: {}, grade: {}, state: {} }}",
self.name, self.age, self.school, self.major, self.grade, self.state)
}
}
fn main() {
let school = String::from("東南大學(xué)");
let major = String::from("土木工程學(xué)院");
let s = Student {
name: String::from("楊程"),
age: 22,
school,
major,
grade: String::from("大三"),
state: true,
};
println!("{:?}", s);
}輸出:
Student { name: 楊程, age: 22, school: 東南大學(xué), major: 土木工程學(xué)院, grade: 大三, state: true }
2. impl fmt::Display for Student
返回值:fmt::Result; 調(diào)用:println!("{}", s); {}里不需要:?
use std::fmt;
struct Point {
x: i32,
y: i32,
}
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
impl Point {
fn distance(&self, other: &Point) -> f32 {
let x_diff = self.x - other.x;
let y_diff = self.y - other.y;
((x_diff * x_diff + y_diff * y_diff) as f32).sqrt()
}
}
fn main() {
let p1 = Point { x: 3, y: 0 };
let p2 = Point { x: 0, y: 4 };
println!("Distance between {} and {} is {}.", p1, p2, p1.distance(&p2));
}輸出:
Distance between Point(3, 0) and Point(0, 4) is 5.
輸出要與使用#[derive(Debug)]時(shí)一樣,只要修改write宏的第2個(gè)參數(shù),如:
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Point {{ x: {}, y: {} }}", self.x, self.y)
}
}#[derive(PartialEq)]
使用#[derive(PartialEq)]為結(jié)構(gòu)體自動(dòng)實(shí)現(xiàn)了PartialEq trait。這使得可以直接使用==運(yùn)算符比較兩個(gè)結(jié)構(gòu)體實(shí)例的相等性。
例1:
#[derive(PartialEq)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let point1 = Point { x: 10, y: 20 };
let point2 = Point { x: 10, y: 20 };
if point1 == point2 {
println!("The two points are equal.");
} else {
println!("The two points are not equal.");
}
}輸出:
The two points are equal.
例2:
#[derive(Debug, PartialEq)]
struct Person {
name: String,
age: u32,
}
fn main() {
let person1 = Person {
name: String::from("Alice"),
age: 25,
};
let person2 = Person {
name: String::from("Bob"),
age: 30,
};
let person3 = Person {
name: String::from("Alice"),
age: 25,
};
println!("Is {:?} equal to {:?}? {}", person1, person2, person1 == person2);
println!("Is {:?} equal to {:?}? {}", person1, person3, person1 == person3);
}
輸出:
Is Person { name: "Alice", age: 25 } equal to Person { name: "Bob", age: 30 }? false
Is Person { name: "Alice", age: 25 } equal to Person { name: "Alice", age: 25 }? true
#[derive(Default)]
調(diào)用#[derive(Default)],相當(dāng)于創(chuàng)建一個(gè)默認(rèn)的結(jié)構(gòu)體實(shí)例,每一個(gè)字段都是對(duì)應(yīng)數(shù)據(jù)類(lèi)型的默認(rèn)值,無(wú)需手動(dòng)為每個(gè)字段設(shè)置默認(rèn)值。
例1:
#[derive(Default,Debug)]
struct Circle {
radius: f32,
}
impl Circle {
fn area(&self) -> f32 {
let pi = std::f32::consts::PI;
pi * self.radius * self.radius
}
}
fn main() {
let mut c = Circle::default();
println!("Circular area of {:?} = {}.", c, c.area());
c.radius = 1.0;
println!("Circular area of {:?} = {}.", c, c.area());
}輸出:
Circular area of Circle { radius: 0.0 } = 0.
Circular area of Circle { radius: 1.0 } = 3.1415927.
例2:
#[derive(Debug, Default)]
struct Student {
name: String,
age: u32,
school: String,
major: String,
grade: String,
state: bool,
}
fn main() {
let mut s1 = Student::default();
println!("{:?}", s1);
s1.name = String::from("楊程");
s1.age = 22;
s1.school = String::from("東南大學(xué)");
s1.major = String::from("土木工程學(xué)院");
s1.grade = String::from("大三");
s1.state = true;
println!("{:?}", s1);
let s2 = Student {
age: 23,
grade: String::from("大四"),
..s1 //注意這里的結(jié)構(gòu)體更新語(yǔ)法
};
println!("{:?}", s2);
}輸出:
Student { name: "", age: 0, school: "", major: "", grade: "", state: false }
Student { name: "楊程", age: 22, school: "東南大學(xué)", major: "土木工程學(xué)院", grade: "大三", state: true }
Student { name: "楊程", age: 23, school: "東南大學(xué)", major: "土木工程學(xué)院", grade: "大四", state: true }
此例還有一個(gè)rust結(jié)構(gòu)體的特殊用法,當(dāng)結(jié)構(gòu)體大部分字段需要被設(shè)置成與現(xiàn)存的另一個(gè)結(jié)構(gòu)體的一樣,僅需更改其中的一兩個(gè)字段的值,可以使用結(jié)構(gòu)體更新語(yǔ)法,在現(xiàn)存的結(jié)構(gòu)體名前加上兩個(gè)連續(xù)的句號(hào):“..Struct_Name”。
#[derive(Clone)]
Clone 在復(fù)制過(guò)程中對(duì)所有字段進(jìn)行逐個(gè)復(fù)制,包括所有引用類(lèi)型和原始類(lèi)型。這意味著每次進(jìn)行克隆時(shí),都會(huì)創(chuàng)建新的數(shù)據(jù)副本。
示例:
#[derive(Clone)]
struct Person {
name: String,
age: i32,
}
fn main() {
let mut person1 = Person { name: String::new(), age: 0 };
let mut person2 = person1.clone();
person1.name = "Alice".to_string();
person1.age = 22;
println!("Person 1: {}, {}", person1.name, person1.age);
println!("Person 2: {}, {}", person2.name, person2.age);
person2 = person1.clone();
println!("Person 2: {}, {}", person2.name, person2.age);
}
輸出:
Person 1: Alice, 22
Person 2: , 0
Person 2: Alice, 22
其他相關(guān)內(nèi)容
模式匹配
結(jié)構(gòu)體可用 模式匹配(Pattern Matching)來(lái)解構(gòu)和訪問(wèn)其字段。
例1:
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 10, y: 20 };
match p {
Point { x, y } => {
println!("x:{}, y: {}", x, y);
}
}
}例2:
struct Time {
hour: i32,
minute: i32,
second: i32,
}
fn main() {
let t = Time { hour: 10, minute: 30, second: 45 };
match t {
Time { hour, minute, second } => {
print!("The time is {}:", hour);
println!("{}:{}", minute, second);
}
}
}結(jié)構(gòu)體大小
結(jié)構(gòu)體的大小在C/C++中使用運(yùn)算符 sizeof 來(lái)計(jì)算;在Rust語(yǔ)言中,則使用標(biāo)準(zhǔn)庫(kù)中的一個(gè)模塊std::mem::中的size_of和size_of_val,它提供了與內(nèi)存管理相關(guān)的函數(shù)。
1. std::mem::size_of
用于計(jì)算給定類(lèi)型的大小,不接受任何參數(shù)。這個(gè)函數(shù)返回一個(gè)給定類(lèi)型的大?。ㄒ宰止?jié)為單位)。它是一個(gè)泛型函數(shù),可以用于任何類(lèi)型。
示例:
#![allow(dead_code)]
struct Point {
x: i32,
y: i32,
}
struct Person {
name: String,
age: i32,
height: f32,
is_employed: bool,
}
fn main() {
let point = Point { x: 10, y: 20 };
println!("Size of Point: {}", std::mem::size_of::<Point>());
let person = Person {
name: "Hann Yang".to_string(),
age: 50,
height: 1.72,
is_employed: true,
};
println!("Size of Person: {}", std::mem::size_of::<Person>());
}輸出:
Size of Point: 8
Size of Person: 40
2. std::mem::size_of_val
用于計(jì)算給定值的大小,接受一個(gè)值作為參數(shù)。它用于獲取一個(gè)值的大?。ㄒ宰止?jié)為單位)。與 size_of 函數(shù)不同的是,size_of_val 函數(shù)可以用于任何值,而非類(lèi)型。
示例:
#![allow(dead_code)]
struct Point {
x: i32,
y: i32,
}
struct Person {
name: String,
age: i32,
height: f32,
is_employed: bool,
}
fn main() {
let point = Point { x: 10, y: 20 };
println!("Size of Point: {}", std::mem::size_of_val(&point));
let person = Person {
name: "Hann Yang".to_string(),
age: 50,
height: 1.72,
is_employed: true,
};
println!("Size of Person: {}", std::mem::size_of_val(&person));
}輸出:
Size of Point: 8
Size of Person: 40
注意:在這兩個(gè)例子中,計(jì)算類(lèi)型大小和值大小的結(jié)果都是相同的,因?yàn)檫@里沒(méi)有涉及到指針或其他復(fù)雜的情況。
本文總結(jié)
結(jié)構(gòu)體是Rust中一種重要的數(shù)據(jù)結(jié)構(gòu),用于組織不同類(lèi)型的字段。以下是結(jié)構(gòu)體的重點(diǎn)內(nèi)容的總結(jié):
- 結(jié)構(gòu)體定義:使用
struct關(guān)鍵字來(lái)定義結(jié)構(gòu)體,結(jié)構(gòu)體可以包含多個(gè)字段,每個(gè)字段可以有不同的類(lèi)型。 - 結(jié)構(gòu)體實(shí)例:定義一個(gè)結(jié)構(gòu)體后,可以使用結(jié)構(gòu)體名稱(chēng)來(lái)創(chuàng)建結(jié)構(gòu)體實(shí)例,通過(guò)
.運(yùn)算符來(lái)訪問(wèn)結(jié)構(gòu)體字段。 - 結(jié)構(gòu)體分類(lèi):結(jié)構(gòu)體可以分為三種類(lèi)型:?jiǎn)卧Y(jié)構(gòu)體(
())、元組結(jié)構(gòu)體(用逗號(hào)分隔的多個(gè)字段)和具名結(jié)構(gòu)體(有自定義名稱(chēng)的字段)。 - 結(jié)構(gòu)體嵌套:結(jié)構(gòu)體可以嵌套,用于組織和存儲(chǔ)復(fù)雜的數(shù)據(jù)。
- 結(jié)構(gòu)體方法:結(jié)構(gòu)體可以定義方法,用于在結(jié)構(gòu)體上執(zhí)行操作。結(jié)構(gòu)體方法與關(guān)聯(lián)函數(shù)類(lèi)似,但只能在結(jié)構(gòu)體上調(diào)用。
- 關(guān)聯(lián)函數(shù):通過(guò)
impl關(guān)鍵字在結(jié)構(gòu)體上定義關(guān)聯(lián)函數(shù),用于在結(jié)構(gòu)體實(shí)例上執(zhí)行特定操作。關(guān)聯(lián)函數(shù)可以是普通函數(shù)或方法。 - 自定義打印宏:使用
derive(Debug)]來(lái)自動(dòng)實(shí)現(xiàn)fmt::Debugtrait,實(shí)現(xiàn)自定義的打印輸出格式。 - 其他相關(guān)內(nèi)容:結(jié)構(gòu)體可以通過(guò)
derive屬性來(lái)自動(dòng)實(shí)現(xiàn)其他trait,如PartialEq(部分相等性)、Default(默認(rèn)值)和Clone(克?。?/li> - 結(jié)構(gòu)體大?。涸赗ust中,結(jié)構(gòu)體的內(nèi)存大小是固定的,可以在定義時(shí)指定大小,也可以使用
#[repr(C)]來(lái)指定大小和布局。 - 模式匹配:可以使用模式匹配來(lái)訪問(wèn)和匹配結(jié)構(gòu)體的字段,這使得在編寫(xiě)代碼時(shí)更加靈活和方便。
總的來(lái)說(shuō),結(jié)構(gòu)體是Rust中非常強(qiáng)大和靈活的數(shù)據(jù)結(jié)構(gòu),可以用于組織和操作各種類(lèi)型的數(shù)據(jù)。通過(guò)使用結(jié)構(gòu)體、方法、關(guān)聯(lián)函數(shù)和其他相關(guān)特性,可以輕松地實(shí)現(xiàn)復(fù)雜的數(shù)據(jù)結(jié)構(gòu)和算法。
到此這篇關(guān)于Rust數(shù)據(jù)類(lèi)型之結(jié)構(gòu)體Struct的使用的文章就介紹到這了,更多相關(guān)Rust 結(jié)構(gòu)體Struct內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Rust?Atomics?and?Locks內(nèi)存序Memory?Ordering詳解
這篇文章主要為大家介紹了Rust?Atomics?and?Locks內(nèi)存序Memory?Ordering詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02
rust類(lèi)型轉(zhuǎn)換的實(shí)現(xiàn)
Rust是類(lèi)型安全的語(yǔ)言,因此在Rust中做類(lèi)型轉(zhuǎn)換不是一件簡(jiǎn)單的事,本文主要介紹了rust類(lèi)型轉(zhuǎn)換的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2023-12-12
使用Rust制作康威生命游戲的實(shí)現(xiàn)代碼
這篇文章主要介紹了使用Rust制作康威生命游戲,初始rust項(xiàng)目,使用wasm的項(xiàng)目模板,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-09-09
Rust如何進(jìn)行模塊化開(kāi)發(fā)技巧分享
Rust模塊化,模塊化有助于代碼的管理和層次邏輯的清晰,本文主要介紹了Rust如何進(jìn)行模塊化開(kāi)發(fā),結(jié)合實(shí)例代碼給大家講解的非常詳細(xì),需要的朋友可以參考下2023-01-01
Rust生成隨機(jī)數(shù)的項(xiàng)目實(shí)踐
Rust標(biāo)準(zhǔn)庫(kù)中并沒(méi)有隨機(jī)數(shù)生成器,常見(jiàn)的解決方案是使用rand包,本文主要介紹了Rust生成隨機(jī)數(shù)的項(xiàng)目實(shí)踐,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03

