• Rust 数据类型 之 结构体(Struct)


    目录

    结构体(Struct)

    定义与声明

    结构体定义

    结构体实例

    结构体分类

    单元结构体(Unit Struct)

    元组结构体(Tuple Struct)

    具名结构体(Named Struct)

    结构体嵌套

    结构体方法

    例1:结构体转换为字符串描述

    例2:矩形的周长和面积

    例3:结构体字段的更新与输出

    关联函数

    结构体方法与关联函数的区别

    参数传递方式的区别

    使用方式的区别

    结构体的trait

    #[derive(Debug)]

    例1:

    例2:

    自定义打印宏 

    1. impl fmt::Debug for Student

    2. impl fmt::Display for Student

    #[derive(PartialEq)]

    例1:

    例2:

    #[derive(Default)]

    例1:

    例2:

    #[derive(Clone)]

    其他相关内容

    模式匹配

    例1:

    例2:

    结构体大小

    1. std::mem::size_of

    2. std::mem::size_of_val

    本文总结


    结构体(Struct)

    是一种自定义数据类型,允许将多个相关的值组合在一起,形成一个更复杂的数据结构。结构体被广泛应用于组织和管理数据,具有灵活性和强大的表达能力。

    定义与声明

    结构体定义

    在Rust中,定义和声明结构体的语法如下:

    1. struct Name {
    2. field1: Type1,
    3. field2: Type2,
    4. // ...
    5. fieldN: TypeN,
    6. }

    其中,Name是结构体的名称,每个数据名及其对应的数据类型组成一个字段,field1fieldN是结构体的字段名称,Type1TypeN是字段的数据类型

    通过关键字 struct 定义,指定结构体名称,结构体内用 field:type, 表示字段名称及数据类型,注意rust语言不能在定义的同时进行赋值,且用逗号分隔各字段,不像c/c++用分号

    结构体中可以根据需要定义字段个数,理论上要多少就定义多少;但实际上字段太多,结构体也会变得很占空间,对程序的空间效率是个负担。

    结构体实例

    如以下代码定义了一个名为Point的结构体,包含x和y两个字段,类型分别为i32和f64:

    struct Point {
        x: i32,
        y: f64,
    }

    定义结构体后,可以像使用其他类型一样使用它。例如,可以声明一个Point类型的变量,并为其字段赋值

    let my_point = Point { x: 10, y: 20.0 };

    使用结构体时,用成员运算符 my_point.x 来调用对应字段的值:

    println!("({},{})", point.x, point.y);    // 输出:(10,20)

    可变实例

    需要变动字段的值,在声明时需要用 let mut,如:

    1. struct Point {
    2. x: i32,
    3. y: f64,
    4. }
    5. fn main() {
    6. let mut point = Point { x: 10, y: 20.0 };
    7. point.x = 5;
    8. println!("({},{})", point.x, point.y); // 输出:(5,20)
    9. }

    结构体分类

    在Rust中,结构体(Struct)可以按照不同的方式进行分类,以下是一些常见的分类方式:

    单元结构体(Unit Struct)

    这种结构体没有任何字段,它只是用于表示一个空的类型。这种结构体通常用于作为其他结构体的组成部分或返回类型。例如:

    struct UnitStruct;

    元组结构体(Tuple Struct)

    这种结构体包含一组字段,可以通过元组语法来访问每个字段。元组结构体可以用于表示简单的数据集合,不使用大括号{},而是使用元组的小括号()。例如:

    struct TupleStruct(i32, String);

    相当字段数据没有名称的结构体,访问时使用索引。如:

    1. struct Point (i32, f64);
    2. fn main() {
    3. let mut point = Point(10, 20.0);
    4. point.0 = 5;
    5. println!("({},{})", point.0, point.1);
    6. }

    具名结构体(Named Struct)

    这种结构体有一个显式的名称,并且包含一组字段。具名结构体可以用于表示复杂的数据结构,例如一个包含多个字段的对象,本文的示例大多数都为具名结构体,用法已在本文开头讲过:

    struct MyStruct {  
        field1: i32,  
        field2: String,  
        // ...  
    }

    除了以上三种常见的结构体类型,Rust还支持其他特殊类型的结构体,例如带有泛型参数的结构体、具名元组结构体(Named Tuple Struct)和结构体路径(Struct Type Alias)等。

    需要注意的是,在Rust中,结构体的分类并不是强制性的,也就是说,一个结构体可以包含任意类型的字段,并且可以在任何地方使用。这使得结构体非常灵活,可以用于实现各种复杂的数据结构。

    结构体字段的数据类型可以是以下常见的rust数据,甚至可以是函数、引用、指针类型。

    1. 标量类型(Scalar Types):

      • 整数类型(Integer Types):包括有符号整数类型和无符号整数类型。常见的整数类型有 i8i16i32i64i128 表示有符号整数,u8u16u32u64u128 表示无符号整数。此外,还有 isize 和 usize,它们根据平台的位数自动调整大小。
      • 浮点数类型(Floating-Point Number Types):包括 f32 和 f64 两种类型,表示单精度和双精度浮点数。
      • 布尔类型(Boolean Type):只有两个取值,true 和 false
      • 字符类型(Character Type):表示单个 Unicode 字符,通常存储为 4 个字节。
    2. 复合类型(Composite Types):

      • 数组类型(Array Types):由相同类型的元素组成的有限集合。可以通过固定长度或动态长度来定义数组。
      • 切片类型(Slice Types):对一个连续的内存块进行引用,可以看作是动态数组。切片类型提供了访问和操作数据的一种高效方式。
      • 元组类型(Tuple Types):一种将多个不同类型的值组合在一起的数据结构,用圆括号和逗号分隔的元素序列表示。元组可以包含不同类型的元素,例如整数、浮点数、布尔值、字符串等。
      • 结构体类型(Struct Types):一种自定义的数据类型,可以包含多个不同类型的字段。结构体可以通过定义来指定其字段和属性。
      • 枚举类型(Enum Types):表示一个可能取多个值的变量。在 Rust 中,枚举类型使用 enum 关键字定义,每个可能的取值都是一个不同的枚举成员。

    结构体嵌套

    一个结构体可以包含任意类型的字段,当然也包括结构体。

    在以下这个例子中,Address 结构体包含了 street、city 和 state 三个字段,而 Person 结构体则包含了 name、age 和 address 三个字段,其中 address 字段的类型是 Address 结构体。

    1. struct Address {
    2. street: String,
    3. city: String,
    4. state: String,
    5. }
    6. struct Person {
    7. name: String,
    8. age: u8,
    9. address: Address,
    10. }

    结构体方法

    方法(method)是在结构体上定义的功能,可以访问结构体的字段并执行一些操作。使用关键字impl,结构体可以对应一个或多个impl代码块。

    例1:结构体转换为字符串描述

    1. struct Student {
    2. name:String,
    3. age:u32,
    4. school:String,
    5. major:String,
    6. grade:String,
    7. state:bool
    8. }
    9. impl Student {
    10. fn to_string(&self) -> String {
    11. format!("Student {{ name: {}, age: {}, school: {}, major: {}, grade: {}, state: {} }}",
    12. self.name, self.age, self.school, self.major, self.grade, self.state)
    13. }
    14. }
    15. fn main() {
    16. let school = String::from("东南大学");
    17. let major = String::from("土木工程学院");
    18. let s = Student{
    19. name:String::from("杨程"),
    20. age:22,
    21. school,
    22. major,
    23. grade:String::from("大三"),
    24. state:true
    25. };
    26. println!("{}", s.to_string());
    27. }

    输出:

    Student { name: 杨程, age: 22, school: 东南大学, major: 土木工程学院, grade: 大三, state: true }

    注意:上例中有一个rust结构体的特殊用法,使用同名变量在结构体外为对应字段赋值。

    例2:矩形的周长和面积

    1. struct Rectangle {
    2. width: f32,
    3. height: f32,
    4. }
    5. impl Rectangle {
    6. // 构造函数
    7. fn new(width: f32, height: f32) -> Rectangle {
    8. Rectangle { width, height }
    9. }
    10. // 计算矩形的面积
    11. fn area(&self) -> f32 {
    12. self.width * self.height
    13. }
    14. // 计算矩形的周长
    15. fn perimeter(&self) -> f32 {
    16. (self.width + self.height) * 2.0
    17. }
    18. }
    19. impl Rectangle {
    20. // 判断矩形是否相等
    21. fn is_equal(&self, other: &Rectangle) -> bool {
    22. self.width == other.width && self.height == other.height
    23. }
    24. }
    25. fn main() {
    26. let rect1 = Rectangle::new(5.0, 6.0);
    27. let rect2 = Rectangle::new(5.0, 6.0);
    28. println!("Rectangle 1 area: {}", rect1.area());
    29. println!("Rectangle 1 perimeter: {}", rect1.perimeter());
    30. println!("Rectangle 2 area: {}", rect2.area());
    31. println!("Rectangle 2 perimeter: {}", rect2.perimeter());
    32. if rect1.is_equal(&rect2) {
    33. println!("Rectangles are equal");
    34. } else {
    35. println!("Rectangles are not equal");
    36. }
    37. }

    输出:

    Rectangle 1 area: 30
    Rectangle 1 perimeter: 22
    Rectangle 2 area: 30
    Rectangle 2 perimeter: 22
    Rectangles are equal 

    例3:结构体字段的更新与输出

    1. struct Person {
    2. name: String,
    3. age: u32,
    4. }
    5. impl Person {
    6. // 这是构造函数,用于创建一个新的 Person 实例
    7. fn new(name: String, age: u32) -> Person {
    8. Person { name, age }
    9. }
    10. fn say_hello(&self) {
    11. println!("Hello, my name is {} and I'm {}.", self.name, self.age);
    12. }
    13. fn update_age(&mut self, new_age: u32) {
    14. self.age = new_age;
    15. }
    16. fn update_name(&mut self, new_name: String) {
    17. self.name = new_name;
    18. }
    19. }
    20. fn main() {
    21. // 创建一个新的 Person 实例
    22. let mut person = Person::new("Tom".to_string(), 5);
    23. // 调用 say_hello 方法,输出 Person 的信息
    24. person.say_hello();
    25. // 调用 update_age 方法,更新 Person 的年龄
    26. person.update_age(3);
    27. // 再次调用 say_hello 方法,输出更新后的信息
    28. person.say_hello();
    29. person.update_age(5);
    30. person.update_name(String::from("Jerry"));
    31. person.say_hello();
    32. }

    输出:

    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.

    关联函数

    之所以"结构体方法"不叫"结构体函数"是因为"函数"这个名字留给了这种函数:它在 impl 块中却没有 &self 参数。这种函数不依赖实例,但是使用它需要声明是在哪个 impl 块中的,比如上小节例2和例3中的构造函数new()就是关联函数,类似于字符串函数String::new(),String::from("Jerry")。

    示例:

    1. #[derive(Debug,Clone)]
    2. struct Rectangle {
    3. width: u32,
    4. height: u32,
    5. }
    6. impl Rectangle {
    7. fn create(width: u32, height: u32) -> Rectangle {
    8. Rectangle { width, height }
    9. }
    10. fn area(self) -> u32 {
    11. self.width * self.height
    12. }
    13. fn area2(&self) -> u32 {
    14. self.width * self.height
    15. }
    16. }
    17. fn main() {
    18. let rect = Rectangle::create(30, 50);
    19. println!("{:?}", rect);
    20. println!("Area: {}", Rectangle::area(rect.clone()));
    21. println!("Area: {}", rect.area2());
    22. }

    输出:

    Rectangle { width: 30, height: 50 }
    Area: 1500
    Area: 1500

    结构体方法与关联函数的区别

    参数传递方式的区别

    结构体方法:结构体方法默认情况下是可变的(mutable),也就是说可以修改结构体的字段。在调用方法时,可以通过引用(&self)或可变引用(&mut self)来传递结构体实例,以便修改其字段。例如:my_struct.my_method(&mut my_struct)。

    关联函数:关联函数默认情况下是不可变的(immutable),也就是说无法修改结构体的字段。在调用函数时,只能通过常量引用(&self)来传递结构体实例,因为常量引用是只读的。例如:let my_struct = MyStruct {...}; my_struct.my_function()。

    使用方式的区别

    结构体方法:结构体方法可以直接在结构体实例上调用,无需显式传递结构体实例。例如:my_struct.my_method()。

    关联函数:关联函数需要显式传递结构体实例作为参数。例如:MyStruct::my_function(my_struct)。

    结构体的trait

    Rust 中的 trait 是一种抽象类型,用于定义泛型行为,trait 可以理解为一种接口。trait 使用关键字 derive 来自动生成实现。通过使用 derive,可以避免手动编写冗长的代码,提高代码的可读性和可维护性。trait 有很多,比如Copy,Clone,Debug,Default,Drop,Hash,Ord,PartialOrd,Send,Sync等等,先挑几种最常用的学一下:

    #[derive(Debug)]

    在 Rust 语言中用于自动生成一个结构体的 Debug 实现,Debug 是 Rust 标准库中的一个 trait,用于在控制台打印调试信息。

    使用 #[derive(Debug)] 属性可以为结构体自动生成一个 Debug 实现,这样在需要打印调试信息时,就可以使用 {:?} 格式化字符串来打印该结构体的内容。例如,在上面的代码中,s 结构体的 Debug 实现已经被自动生成,因此可以使用 println!("{:?}", s) 来打印出结构体 s 的内容。

    例1:
    1. #[derive(Debug)]
    2. struct Point {
    3. x: i32,
    4. y: i32,
    5. }
    6. impl Point {
    7. fn distance(&self, other: &Point) -> f32 {
    8. let x_diff = self.x - other.x;
    9. let y_diff = self.y - other.y;
    10. ((x_diff * x_diff + y_diff * y_diff) as f32).sqrt()
    11. }
    12. }
    13. fn main() {
    14. let p1 = Point { x: 3, y: 0 };
    15. let p2 = Point { x: 0, y: 4 };
    16. println!("Distance between {:?} and {:?} is {}.", p1, p2, p1.distance(&p2));
    17. }

    输出:

    Distance between Point { x: 3, y: 0 } and Point { x: 0, y: 4 } is 5. 

    例2:
    1. #[derive(Debug)]
    2. struct Student {
    3. name: String,
    4. age: u32,
    5. school: String,
    6. major: String,
    7. grade: String,
    8. state: bool,
    9. }
    10. impl Student {
    11. fn new() -> Student {
    12. return Student {
    13. age: 0,
    14. name: String::new(),
    15. school: String::from(""),
    16. major: "".to_string(),
    17. grade: "".to_string(),
    18. state: false,
    19. };
    20. }
    21. }
    22. fn main() {
    23. let mut s = Student::new();
    24. s.name = String::from("杨程");
    25. s.age = 22;
    26. s.school = String::from("东南大学");
    27. s.major = String::from("土木工程学院");
    28. s.grade = String::from("大三");
    29. s.state = true;
    30. println!("{:?}", s);
    31. }

    输出:

    Student { name: "杨程", age: 22, school: "东南大学", major: "土木工程学院", grade: "大三", state: true } 

    与上一小节的例2对比,输出内容基本一致,就多了String的引号标记。相比自动生成 Debug 实现可以简化代码编写过程,并且可以避免手动实现 Debug 时可能出现的错误。

    在本例中,使用宏打印结构体println!("{:?}", s);时,第一行的代码#[derive(Debug)]是必须的,如果去掉就会报错:

    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; 调用:println!("{:?}", s);

    1. use std::fmt;
    2. struct Student {
    3. name: String,
    4. age: u32,
    5. school: String,
    6. major: String,
    7. grade: String,
    8. state: bool,
    9. }
    10. impl fmt::Debug for Student {
    11. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    12. write!(f,
    13. "Student {{ name: {}, age: {}, school: {}, major: {}, grade: {}, state: {} }}",
    14. self.name, self.age, self.school, self.major, self.grade, self.state)
    15. }
    16. }
    17. fn main() {
    18. let school = String::from("东南大学");
    19. let major = String::from("土木工程学院");
    20. let s = Student {
    21. name: String::from("杨程"),
    22. age: 22,
    23. school,
    24. major,
    25. grade: String::from("大三"),
    26. state: true,
    27. };
    28. println!("{:?}", s);
    29. }

    输出:

    Student { name: 杨程, age: 22, school: 东南大学, major: 土木工程学院, grade: 大三, state: true }  

    2. impl fmt::Display for Student

    返回值:fmt::Result; 调用:println!("{}", s); {}里不需要:?

    1. use std::fmt;
    2. struct Point {
    3. x: i32,
    4. y: i32,
    5. }
    6. impl fmt::Display for Point {
    7. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    8. write!(f, "({}, {})", self.x, self.y)
    9. }
    10. }
    11. impl Point {
    12. fn distance(&self, other: &Point) -> f32 {
    13. let x_diff = self.x - other.x;
    14. let y_diff = self.y - other.y;
    15. ((x_diff * x_diff + y_diff * y_diff) as f32).sqrt()
    16. }
    17. }
    18. fn main() {
    19. let p1 = Point { x: 3, y: 0 };
    20. let p2 = Point { x: 0, y: 4 };
    21. println!("Distance between {} and {} is {}.", p1, p2, p1.distance(&p2));
    22. }

    输出:

    Distance between Point(3, 0) and Point(0, 4) is 5.

    输出要与使用#[derive(Debug)]时一样,只要修改write宏的第2个参数,如:

    1. impl fmt::Display for Point {
    2. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    3. write!(f, "Point {{ x: {}, y: {} }}", self.x, self.y)
    4. }
    5. }

    #[derive(PartialEq)]

    使用#[derive(PartialEq)]为结构体自动实现了PartialEq trait。这使得可以直接使用==运算符比较两个结构体实例的相等性。

    例1:
    1. #[derive(PartialEq)]
    2. struct Point {
    3. x: i32,
    4. y: i32,
    5. }
    6. fn main() {
    7. let point1 = Point { x: 10, y: 20 };
    8. let point2 = Point { x: 10, y: 20 };
    9. if point1 == point2 {
    10. println!("The two points are equal.");
    11. } else {
    12. println!("The two points are not equal.");
    13. }
    14. }

    输出:

    The two points are equal.

    例2:
    1. #[derive(Debug, PartialEq)]
    2. struct Person {
    3. name: String,
    4. age: u32,
    5. }
    6. fn main() {
    7. let person1 = Person {
    8. name: String::from("Alice"),
    9. age: 25,
    10. };
    11. let person2 = Person {
    12. name: String::from("Bob"),
    13. age: 30,
    14. };
    15. let person3 = Person {
    16. name: String::from("Alice"),
    17. age: 25,
    18. };
    19. println!("Is {:?} equal to {:?}? {}", person1, person2, person1 == person2);
    20. println!("Is {:?} equal to {:?}? {}", person1, person3, person1 == person3);
    21. }

    输出:

    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)]

    调用#[derive(Default)],相当于创建一个默认的结构体实例,每一个字段都是对应数据类型的默认值,无需手动为每个字段设置默认值。

    例1:
    1. #[derive(Default,Debug)]
    2. struct Circle {
    3. radius: f32,
    4. }
    5. impl Circle {
    6. fn area(&self) -> f32 {
    7. let pi = std::f32::consts::PI;
    8. pi * self.radius * self.radius
    9. }
    10. }
    11. fn main() {
    12. let mut c = Circle::default();
    13. println!("Circular area of {:?} = {}.", c, c.area());
    14. c.radius = 1.0;
    15. println!("Circular area of {:?} = {}.", c, c.area());
    16. }

    输出:

    Circular area of Circle { radius: 0.0 } = 0.
    Circular area of Circle { radius: 1.0 } = 3.1415927.

    例2:
    1. #[derive(Debug, Default)]
    2. struct Student {
    3. name: String,
    4. age: u32,
    5. school: String,
    6. major: String,
    7. grade: String,
    8. state: bool,
    9. }
    10. fn main() {
    11. let mut s1 = Student::default();
    12. println!("{:?}", s1);
    13. s1.name = String::from("杨程");
    14. s1.age = 22;
    15. s1.school = String::from("东南大学");
    16. s1.major = String::from("土木工程学院");
    17. s1.grade = String::from("大三");
    18. s1.state = true;
    19. println!("{:?}", s1);
    20. let s2 = Student {
    21. age: 23,
    22. grade: String::from("大四"),
    23. ..s1 //注意这里的结构体更新语法
    24. };
    25. println!("{:?}", s2);
    26. }

    输出:

    Student { name: "", age: 0, school: "", major: "", grade: "", state: false }
    Student { name: "杨程", age: 22, school: "东南大学", major: "土木工程学院", grade: "大三", state: true }
    Student { name: "杨程", age: 23, school: "东南大学", major: "土木工程学院", grade: "大四", state: true }

    此例还有一个rust结构体的特殊用法,当结构体大部分字段需要被设置成与现存的另一个结构体的一样,仅需更改其中的一两个字段的值,可以使用结构体更新语法,在现存的结构体名前加上两个连续的句号:“..Struct_Name”。

    #[derive(Clone)]

    Clone 在复制过程中对所有字段进行逐个复制,包括所有引用类型和原始类型。这意味着每次进行克隆时,都会创建新的数据副本。 

    示例:

    1. #[derive(Clone)]
    2. struct Person {
    3. name: String,
    4. age: i32,
    5. }
    6. fn main() {
    7. let mut person1 = Person { name: String::new(), age: 0 };
    8. let mut person2 = person1.clone();
    9. person1.name = "Alice".to_string();
    10. person1.age = 22;
    11. println!("Person 1: {}, {}", person1.name, person1.age);
    12. println!("Person 2: {}, {}", person2.name, person2.age);
    13. person2 = person1.clone();
    14. println!("Person 2: {}, {}", person2.name, person2.age);
    15. }

    输出:

    Person 1: Alice, 22
    Person 2: , 0
    Person 2: Alice, 22

    其他相关内容

    模式匹配

    结构体可用 模式匹配(Pattern Matching)来解构和访问其字段。

    例1:
    1. struct Point {
    2. x: i32,
    3. y: i32,
    4. }
    5. fn main() {
    6. let p = Point { x: 10, y: 20 };
    7. match p {
    8. Point { x, y } => {
    9. println!("x:{}, y: {}", x, y);
    10. }
    11. }
    12. }
    例2:
    1. struct Time {
    2. hour: i32,
    3. minute: i32,
    4. second: i32,
    5. }
    6. fn main() {
    7. let t = Time { hour: 10, minute: 30, second: 45 };
    8. match t {
    9. Time { hour, minute, second } => {
    10. print!("The time is {}:", hour);
    11. println!("{}:{}", minute, second);
    12. }
    13. }
    14. }

    结构体大小

    结构体的大小在C/C++中使用运算符 sizeof 来计算;在Rust语言中,则使用标准库中的一个模块std::mem::中的size_of和size_of_val,它提供了与内存管理相关的函数。

    1. std::mem::size_of

    用于计算给定类型的大小,不接受任何参数。这个函数返回一个给定类型的大小(以字节为单位)。它是一个泛型函数,可以用于任何类型。

    示例:

    1. #![allow(dead_code)]
    2. struct Point {
    3. x: i32,
    4. y: i32,
    5. }
    6. struct Person {
    7. name: String,
    8. age: i32,
    9. height: f32,
    10. is_employed: bool,
    11. }
    12. fn main() {
    13. let point = Point { x: 10, y: 20 };
    14. println!("Size of Point: {}", std::mem::size_of::());
    15. let person = Person {
    16. name: "Hann Yang".to_string(),
    17. age: 50,
    18. height: 1.72,
    19. is_employed: true,
    20. };
    21. println!("Size of Person: {}", std::mem::size_of::());
    22. }

    输出:

    Size of Point: 8
    Size of Person: 40 

    2. std::mem::size_of_val

    用于计算给定值的大小,接受一个值作为参数。它用于获取一个值的大小(以字节为单位)。与 size_of 函数不同的是,size_of_val 函数可以用于任何值,而非类型。

    示例:

    1. #![allow(dead_code)]
    2. struct Point {
    3. x: i32,
    4. y: i32,
    5. }
    6. struct Person {
    7. name: String,
    8. age: i32,
    9. height: f32,
    10. is_employed: bool,
    11. }
    12. fn main() {
    13. let point = Point { x: 10, y: 20 };
    14. println!("Size of Point: {}", std::mem::size_of_val(&point));
    15. let person = Person {
    16. name: "Hann Yang".to_string(),
    17. age: 50,
    18. height: 1.72,
    19. is_employed: true,
    20. };
    21. println!("Size of Person: {}", std::mem::size_of_val(&person));
    22. }

    输出:

    Size of Point: 8
    Size of Person: 40 

    注意:在这两个例子中,计算类型大小和值大小的结果都是相同的,因为这里没有涉及到指针或其他复杂的情况。 


    本文总结

    结构体是Rust中一种重要的数据结构,用于组织不同类型的字段。以下是结构体的重点内容的总结:

    • 结构体定义:使用struct关键字来定义结构体,结构体可以包含多个字段,每个字段可以有不同的类型。
    • 结构体实例:定义一个结构体后,可以使用结构体名称来创建结构体实例,通过.运算符来访问结构体字段。
    • 结构体分类:结构体可以分为三种类型:单元结构体(())、元组结构体(用逗号分隔的多个字段)和具名结构体(有自定义名称的字段)。
    • 结构体嵌套:结构体可以嵌套,用于组织和存储复杂的数据。
    • 结构体方法:结构体可以定义方法,用于在结构体上执行操作。结构体方法与关联函数类似,但只能在结构体上调用。
    • 关联函数:通过impl关键字在结构体上定义关联函数,用于在结构体实例上执行特定操作。关联函数可以是普通函数或方法。
    • 自定义打印宏:使用derive(Debug)]来自动实现fmt::Debug trait,实现自定义的打印输出格式。
    • 其他相关内容:结构体可以通过derive属性来自动实现其他trait,如PartialEq(部分相等性)、Default(默认值)和Clone(克隆)。
    • 结构体大小:在Rust中,结构体的内存大小是固定的,可以在定义时指定大小,也可以使用#[repr(C)]来指定大小和布局。
    • 模式匹配:可以使用模式匹配来访问和匹配结构体的字段,这使得在编写代码时更加灵活和方便。

    总的来说,结构体是Rust中非常强大和灵活的数据结构,可以用于组织和操作各种类型的数据。通过使用结构体、方法、关联函数和其他相关特性,可以轻松地实现复杂的数据结构和算法。

  • 相关阅读:
    从GitHub到GitLab,半导体巨头Arm更换阵营的5大理由
    mysql中date/datetime类型自动转go的时间类型time.Time
    什么是去中心化云计算?
    湖仓一体方案有很多,为何偶数的实时湖仓脱颖而出?
    信驰达RF-DG-52PAS Zigbee 3.0协调器Home Assistant上手指南
    Django项目之美多商城遇到的问题记录与解决(一)
    实在智能入选中国信通院最新《高质量数字化转型产品及服务全景图》,领跑AI大模型核心领域
    Java – 从资源文件夹中读取文件
    如何在Linux服务器上安装Anaconda(超详细)
    数据分析案例-基于sklearn随机森林算法探究影响预期寿命的因素
  • 原文地址:https://blog.csdn.net/boysoft2002/article/details/131746997