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

Rust学习教程16 - 结构体struct 结构体 在上一节,我们提到需要一个更高级的数据结构来帮助我们更好的抽象问题,而结构体strct恰恰就是这样的复合数据结构,它是由其它数据类型组合而来, 其它语言也有类似的数据结构,不过可能有不同的名称,例如object、record等。 结构体跟之. 阅读详情

目录

结构体(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中,定义和声明结构体的语法如下:

struct Name {  
    field1: Type1,  
    field2: Type2,  
    // ...  
    fieldN: TypeN,  
}

其中,Name是结构体的名称,每个数据名及其对应的数据类型组成一个字段,field1到fieldN是结构体的字段名称,Type1到TypeN是字段的数据类型。

通过关键字 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,如:

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

结构体分类

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

单元结构体(Unit Struct)

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

struct UnitStruct;

元组结构体(Tuple Struct)

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

struct TupleStruct(i32, String);

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

struct Point (i32, f64);

fn main() {
	let mut point = Point(10, 20.0); 
	point.0 = 5;
    println!("({},{})", point.0, point.1);  
}

具名结构体(Named Struct)

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

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

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

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

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

  1. 标量类型(Scalar Types):

    • 整数类型(Integer Types):包括有符号整数类型和无符号整数类型。常见的整数类型有 i8、i16、i32、i64、i128 表示有符号整数,u8、u16、u32、u64、u128 表示无符号整数。此外,还有 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 结构体。

struct Address {  
    street: String,  
    city: String,  
    state: String,  
}  
  
struct Person {  
    name: String,  
    age: u8,  
    address: Address,  
}

结构体方法

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

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

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("东南大学");
    let major = String::from("土木工程学院");
    let s = Student{
        name:String::from("杨程"),
        age:22,
        school,
        major,
        grade:String::from("大三"),
        state:true
    };
    println!("{}", s.to_string());
}

输出:

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

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

例2:矩形的周长和面积

struct Rectangle {  
    width: f32,  
    height: f32,  
}  
  
impl Rectangle {  
    // 构造函数  
    fn new(width: f32, height: f32) -> Rectangle {  
        Rectangle { width, height }  
    }  
  
    // 计算矩形的面积  
    fn area(&self) -> f32 {  
        self.width * self.height  
    }  
  
    // 计算矩形的周长  
    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:结构体字段的更新与输出

struct Person {  
    name: String,  
    age: u32,  
}  
  
impl Person {  
    // 这是构造函数,用于创建一个新的 Person 实例  
    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() {  
    // 创建一个新的 Person 实例  
    let mut person = Person::new("Tom".to_string(), 5);  
  
    // 调用 say_hello 方法,输出 Person 的信息  
    person.say_hello();  
  
    // 调用 update_age 方法,更新 Person 的年龄  
    person.update_age(3);  
  
    // 再次调用 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.

关联函数

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

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

参数传递方式的区别

结构体方法:结构体方法默认情况下是可变的(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:
#[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("东南大学");
    s.major = String::from("土木工程学院");
    s.grade = String::from("大三");
    s.state = true;
    println!("{:?}", s);
}

输出:

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

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("东南大学");
    let major = String::from("土木工程学院");
    let s = Student {
        name: String::from("杨程"),
        age: 22,
        school,
        major,
        grade: String::from("大三"),
        state: true,
    };  
    println!("{:?}", s);
}

输出:

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

2. impl fmt::Display for Student

返回值:fmt::Result; 调用: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)]时一样,只要修改write宏的第2个参数,如:

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)]为结构体自动实现了PartialEq trait。这使得可以直接使用==运算符比较两个结构体实例的相等性。

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

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

例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("东南大学");  
    s1.major = String::from("土木工程学院");  
    s1.grade = String::from("大三");  
    s1.state = true;  
    println!("{:?}", s1);  
  
    let s2 = Student {  
        age: 23,  
        grade: String::from("大四"),  
        ..s1  //注意这里的结构体更新语法
    };  
    println!("{:?}", s2);  
}

输出:

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

示例:

#[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

其他相关内容

模式匹配

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

例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);  
        }  
    }  
}

结构体大小

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

1. std::mem::size_of

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

示例:

#![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

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

示例:

#![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 

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


本文总结

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

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

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

揭秘Rust中的公共结构体:编织代码的奥秘 Rust语言的魅力在于其安全性和性能,而其中的公共结构体则是编写模块化、可复用代码的关键。通过本文,我们将深入探索Rust中公共结构体的内涵和应用,解锁编程世界的一扇新门。无论是初学者还是经验丰富的开发者,都将从中获益良多,掌握更多编织代码的奥秘。 阅读详情

相关推荐

猿创征文 | 【Rust指南】解析struct 结构体的定义、实例化、方法、所有权、关联函数

书接上文,本篇博客要分享的是Rust 中和结构体有关的知识,包括定义、实例化的特定,方法的格式、所有权问题以及关联函数。所以此篇文章还会涉及到前面讲的Rust 基本数据类型、所有权等知识,大家在对某些知识点感到陌生的时候可以参考此专栏以往的文章。............

叶落秋白的博客 2937

【Rust 基础篇】Rust 结构体详解

在Rust中,我们可以使用struct关键字定义一个结构体。结构体允许我们定义多个字段(Fields),每个字段都有自己的类型和名称。通过将字段组合在一起,我们可以创建自己的数据类型,以便更好地表示和操作数据。在上述示例中,我们定义了一个名为Point的结构体,它具有两个字段x和y,分别是i32类型的整数。本篇博客详细介绍了Rust中结构体的概念、定义语法、实例化、方法、关联函数以及相关特性。结构体是Rust中一种重要且强大的数据类型,它允许我们将多个相关的值组合在一起,形成更复杂的数据结构。

繁依Fanyi的博客 2284

rust 面向对象之Struct、impl、trait关键字使用

1. 前言 rust语言跟C、C++是一个性能级别的语言,在用法上要比C++简单很多。例如:要实现一个web服务,RUST可以通过包管理工具直接安装一个HTTP库,然后使用。而C++则需要手动下载,手动导入相应的文件等等。 总的而言rust是非常值得学习的一门语言,根据项目的不同需求,不同的性能,灵活应用不同的语言。 2. rust 定义类 2. 1 rust 定义类成员变量 利用结构体(stru...

图解AI 9995

rust 初探 -- struct

方法和函数类似:fn 关键字、名称、参数、返回值方法和函数不同之处:方法是在 struct 的上下文中定义第一个参数是 self,表示方法被调用的 struct 实例每个 struct 可以有多个 impl// impl 声明块,在块里面定义方法// 上下文// self 会自动推断为 Rectangle// 可以是 &self,也可以获得其所有权或可变借用// 这样会有更好的代码组织width: 20,println!println!("{:#?}", rec);

shenyongsi的博客 686

一分钟学会MATLAB-数据清洗(含完整代码)

数据清洗是数据分析过程中的一个重要步骤,目的是提高数据的质量,以便进行更有效的分析。% 删除超出阈值的行。% 用线性插值填充缺失值。% 删除包含缺失值的行。% 找到缺失值的位置。% 可视化数据,识别异常值。缺失值是数据清洗中常见的问题。通过以上步骤,你可以有效地清洗数据,使其准备好进行后续的分析和建模。

2402_87132195的博客 3316

解决若依Vue3前后端分离---路由切换时显示白屏

解决基于Vue3若依前后端分离项目中出现的路由正常切换但是就是不显示数据的问题,也就是不发起网络请求的问题。

简单点的博客 1605

Rust语言进阶之关键字:struct用法实例(三十一)

本篇目的:Rust语言进阶之关键字:struct用法实例在Rust语言中,struct(结构体)是一个用于定义自定义数据类型的关键字。结构体允许开发者将多个相关的数据项组合在一起,形成一个新的复合数据类型。每个数据项称为“字段”,这些字段可以是不同类型的数据。结构体是Rust中组织和管理复杂数据的核心构件之一,广泛应用于实现面向对象编程中的数据封装、模型设计以及类型安全等功能。定义结构体struct关键字用于定义结构体,结构体可以包含多个字段,字段可以是任何类型,包括其他结构体、基本类型或者泛型。通过。

Android系统攻城狮 1971

蓝桥杯单片机省一经验分享1:基础篇.含详细代码与应试技巧

含详细代码、驱动修改与应试技巧

qq_53529450的博客 1万+

【Rust自学】5.1. 定义并实例化struct

一文搞定Rust结构体学习

A Rookie in San Domenico School 1866

Stata极简生存分析

1. 导入数据 webuse drugtr,clear *webuse -- Use dataset from Stata website stset,clear *上一行命令导入进来的数据是“生存时间数据”,会比最原始的数据多四列,这一行命令的目的是重置为原始数据,之所以这样做,是为了显示数据处理的全部过程 codebook drug codebook studytime codebook died codebook age *codebook -- Describe data contents 2.

TOP生物信息 2336

16. SAP Fiori Elements 应用里图片字段(Image)的显示原理介绍

很多朋友向我反映,学习了 一段时间的 SAP Fiori Elements 开发,但是感觉整套体系对于自己来说还是个黑盒子,很多技术点,看了 SAP 官方帮助文档后,觉得自己懂了,但是一旦需要自己动手做一些东西出来时,又觉得一片茫然。 其实笔者自己也经历过这个过程。究其原因,还是大家对 Fiori Elements 一些技术细节没有理解,对 SAP 官方的知识点仅仅停留在记忆,甚至是死记硬背上面。 不过没有关系,本教程笔者会刻意设置一些练习,让大家动手,在实战中逐渐熟悉 Fiori Elements 这

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 758

Rust - 初识结构体

结构体和之前介绍过的元组类似,和元组一样,结构体的每一部分可以是不同类型。但不同于元组,结构体需要命名各部分数据以便能清楚的表明其值的意义。由于有了这些名字,结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。定义结构体需要使用struct关键字并给结构体提供一个名字,类似于变量名结构体的名字需要描述它所组合的数据的意义。然后在大括号中,定义每一部分数据的名字和类型,名字和类型之间用分隔,我们称为字段field),不同字段之间用隔开。// 定义结构体age: i32,

nhb687096的博客 725

Open3D 计算点云法向量的夹角【2026最新版】

计算法向量的夹角,博客长期更新,本文最新更新时间为:2026年3月7日。

点云侠的博客 3131

Rust 结构体(Struct)完全指南:使用 struct 组织相关联的数据

本指南以《The Rust Programming Language》第 5 章(仓库路径 [src/ch05-00-structs.md](https://link.gitcode.com/i/7059288486947373d218e0800da2765a) 及其三个分节)为主体,系统讲解 Rust 中自定义数据类型 struct(结构体)的定义、实例化、所有权语义、派生 trait 与方法绑

gitblog_00095的博客 178

MyBatis-Plus 实战:敏感字段自动加解密支持模糊查询

本文基于MyBatis-Plus框架提出了一种全链路敏感字段加密方案。通过自定义TypeHandler实现数据入库自动加密和查询自动解密,结合重写LambdaQueryWrapper处理查询条件加密,并适配多种查询方式。方案核心包括:1)AESUtil工具类提供加解密基础能力;2)EncryptTypeHandler实现字段类型转换;3)实体类通过注解配置加密字段。该方案在保证数据安全的同时,对业务代码侵入性小,支持姓名、手机号等敏感信息的全流程加密处理,满足系统开发的安全需求。

蔡定努 596

基于YOLOv8的农作物病虫害检测系统设计与实现

国内如中国农业大学的科研团队采用改进的Faster R-CNN模型对小麦病害进行检测,取得了较好的效果。农作物病虫害是影响农业生产的重要因素之一,每年因病虫害导致的农作物减产高达20%-40%。YOLO(You Only Look Once)系列算法作为目标检测领域的代表性模型,以其高效、准确的特点在众多领域得到广泛应用。YOLOv8作为该系列的最新版本,在精度和速度上都有显著提升,非常适合农作物病虫害检测这类需要实时处理的应用场景。然而,现有研究仍存在一些不足:一是模型复杂度高,难以部署到移动设备;

YOLO 794

rust编程学习(二):复合数据类型

复合数据类型是由其他类型组合而成的类型。Rust的复合数据类型有元组、数组、结构体、枚举等, 通过一些简单的例子帮助大家快速了解Rust复合类型。

weixin_46564301的博客 1108

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Rust struct详解:数据组织、方法定义、泛型与生命周期完整指南

Rust是一门以内存安全和高性能为核心的系统编程语言。其独特的所有权机制与生命周期标注,在编译期就保证了数据不会产生悬垂引用和内存泄漏。struct作为Rust自定义数据类型的基础工具,将零散字段封装为有语义的整体,是数据建模的核心单元。理解struct的三种形态——经典结构体、元组结构体与单元结构体——并理清与所有权、借用及生命周期的交互,是打通Rust进阶之路的必经环节。从基础语法到常见陷阱,系统梳理struct的方法定义、泛型组合、derive宏及实际工程中的设计套路,帮助开发者在构造健壮数据类型的同

weixin_31240035的博客 314

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Rust代码示例——3.自定义类型

Rust使用struct定义结构体、enum定义枚举类型,并通过const和static声明常量。这两种数据类型创建方式提供了灵活的数据结构设计能力。

fox_lht的专栏 97

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

【编程开发】Rust 语法速查 & 例子 - 数据结构

数据类型和内存位置由关键字定义。1 绑定变量 生存在栈上的同步代码。在 中,这些变量将成为异步状态机的一部分,最终驻留在堆上。 2 严密地来说_可变_和_不可变_并不准确。不可变绑定或共享引用可能仍然包含 Cell ,从而提供 内部可变性 。定义结构体():用于定义包含命名字段的结构体类型。示例: 元组结构体:结构体的一种变体,使用元组形式定义字段。示例: 零大小结构体:定义一个没有任何字段的结构体,不占用内存空间。示例: 定义枚举():用于定义一组相关的命名常量集合。示例: 变体枚举:枚

dnncool的专栏 1548

从 C++ 走向 rust(五):面向对象编程——设计一个泛型类

用简单的例子说明复杂道理:通过编写第一个 rust “类” 趟的坑,介绍如何在 rust 下编写一个类,并加入泛型数据类型的支持。

程序猿视角 756

Rust数据类型

Rust数据类型

m0_54646395的博客 23

Typical项目概览:为什么代数数据类型是数据交换的未来?

Typical是一个基于代数数据类型(ADT)的数据交换工具,它重新定义了现代应用程序之间的数据通信方式。与传统的数据交换格式相比,Typical通过代数数据类型提供了更安全、更灵活的类型系统,确保数据在不同系统间传输时保持一致性和可靠性。 ## 什么是代数数据类型? 代数数据类型是一种强大的类型系统,它允许开发者通过组合简单类型来构建复杂类型。在Typical中,主要有两种代数数据类型:

gitblog_00381的博客 638

Rust入门(二):基础语法

rust入门第二章基本语法,包括了rust的变量定义、数据类型、函数定义、控制流程、struct结构体、枚举类型、控制和option以及match匹配

weixin_46463785的博客 1415

rust-结构体

方法:定义在结构体的上下文的函数,第一个参数必须是self。结构体:用于创建自定义数据类型,关键字是struct。元组结构体:没有字段名只有字段类型。

会呼吸的鱼_的博客 246

Rust专项——结构体详解——自定义数据类型的基石

Rust 中的结构体(Struct)是一种自定义数据类型,用于将多个相关值组合成一个有意义的整体。文章详细介绍了结构体的定义、实例化、字段访问和修改方法,包括基本语法、字段命名规范和嵌套结构体的使用。重点讲解了结构体方法的定义与实现,通过 impl 块为结构体添加功能,如计算面积等操作方法。此外还涵盖了元组结构体、单元结构体等特殊形式,以及结构体更新语法、所有权规则和模式匹配等高级特性。文章最后提供了实际应用示例和常见错误解决方案,帮助开发者掌握 Rust 结构体的核心概念和最佳实践。

红目香薰 1117
上一篇: 力扣C++|一题多解之数学题专场(1)
下一篇: 力扣C++|一题多解之数学题专场(2)
Hann Yang
Hann Yang 优质创作者: 编程框架技术领域 优质创作者: 编程框架技术领域 领域专家: 算法与数据结构技术领域 领域专家: 算法与数据结构技术领域
博客等级 码龄19年 4万+粉丝 1041原创
评论 116
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hann Yang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值