结构体
一、基本概念
- Rust 语言自身有的数据类型,虽说已经挺多,但是有时候并不能满足我们的需要,例如当我们需要一种能存储学生信息的数据类型时,Rust 自有的数据类型是不能做到的,因为一条学生信息记录既有数字又有文字。
- 因此,Rust 像其他编程语言一样,允许开发者根据自己需要定义自定义数据类型,而结构体就是一种自定义数据类型。
1、定义方式
- Rust 语言中的结构体,也是使用关键字 struct 来声明定义的。
- 在我所学习过的编程语言中,支持以结构体来自定义数据类型的,目前只有 C/C++ 和 Rust,Python 与 Java 都没有。
- Rust 中定义结构体的形式如下:
struct 结构体名 { 数据1:数据类型1, 数据2:数据类型2, ... }
- 结构体中,每个数据名及其对应的数据类型组成一个字段,结构体中可以根据需要定义字段个数,理论上要多少就定义多少;但实际上,建议结构体中的字段不要超过 15 个,特别是包含不同数据类型的结构体;因为字段太多,结构体也会变得很占空间,对程序的空间上的效率十个负担。
2、简单的结构体例子
- 以学生信息为例举个简单的结构体例子,其代码如下:
struct Student { name:String, age:u32, grade:String, state:bool }
二、结构体的使用
- 结构体的使用,首先要将结构体实例化。
1、结构体实例化
- 实例化,就是给结构体中的字段赋值;实例过程中结构体字段的顺序应当和声明的时候一样,如下示例:
fn main() { let s1 = Student{ name:String::from("张三"), age:23, grade:String::from("高三"), state:true }; println!("学生{},年纪{},年级{},在学状态{}", s1.name, s1.age, s1.grade, s1.state); } struct Student { name:String, age:u32, grade:String, state:bool } // 输出: // 学生张三,年纪23,年级高三,在学状态true
2、结构体取值和改值
- 由例子也可以看出,取结构体种某个字段的值的方式是:结构体名.字段名,这个和 C/C++ 语言一样。
- 同理,修改结构体中某个字段的值,可以用:结构体名.字段名=新值 形式,如下示例:
fn main() { let mut s1 = Student{ name:String::from("张三"), age:23, grade:String::from("高三"), state:true }; println!("学生{},年纪{},年级{},在学状态{}", s1.name, s1.age, s1.grade, s1.state); s1.grade = String::from("大二"); println!("学生{},年纪{},年级{},在学状态{}", s1.name, s1.age, s1.grade, s1.state); } struct Student { name:String, age:u32, grade:String, state:bool } /*输出 学生张三,年纪23,年级高三,在学状态true 学生张三,年纪23,年级大二,在学状态true */
3、结构体做返回值
- 结构体也可以作为函数的返回值来使用,如下示例:
fn main() { let s2 = build_student(String::from("御承扬"), 21, String::from("大三"), true); println!("学生{},年纪{},年级{},在学状态{}", s2.name, s2.age, s2.grade, s2.state); } struct Student { name: String, age: u32, grade: String, state: bool, } fn build_student(_name: String, _age: u32, _grade: String, _state: bool) -> Student { Student { name: _name, age: _age, grade: _grade, state: _state, } } // 输出 // 学生御承扬,年纪21,年级大三,在学状态true
3.1、变量与字段同名时的字段初始化简写语法
- 当参数名与字段名相同时,可以使用字段初始化简写语法,如下例子:
fn build_student2(name:String, age:u32, grade:String, state:bool) -> Student { Student{ name, age, grade, state } }
4、元组结构体
- 元组结构体,一种和元组类似的结构体。
- 元组结构体有着结构体名称提供的含义,但没有具体的字段名,只有字段的类型。
- 示例:
struct Color(i32, i32, i32); struct Point(i32, i32, i32); let black = Color(0, 0, 0); let origin = Point(0, 0, 0);
5、结构体使用案例
- 首先使用非结构体模式,定义一个简单的函数:求面积,如下:
fn main() { let width1 = 30; let height1 = 50; println!( "The area of the rectangle is {} square pixels.", area(width1, height1) ); } fn area(width: u32, height: u32) -> u32 { width * height }
5.1、使用元组重构
- 接着用元组对上述求面积的函数进行重构:
fn main() { let rect1 = (30, 50); println!( "The area of the rectangle is {} square pixels.", area(rect1) ); } fn area(dimensions: (u32, u32)) -> u32 { dimensions.0 * dimensions.1 }
5.2、使用结构体重构
- 接着受用结构体再次对函数进行重构:
struct Rectangle { width: u32, height: u32, } fn main() { let rect1 = Rectangle { width: 30, height: 50 }; println!( "The area of the rectangle is {} square pixels.", area(&rect1) ); } fn area(rectangle: &Rectangle) -> u32 { rectangle.width * rectangle.height }
- 以上三个例子的输出都是一样的:
The area of the rectangle is 1500 square pixels.
6、使用 println!("{:?}") 输出结构体内容
- 如果直接使用之前的 println!("{}") 来输出结构体的内容,则会报错如下:
error[E0277]: the trait bound `Rectangle: std::fmt::Display` is not satisfied
- 进行适当修改,使用 println!("{:?}") 则可以输出结构体的内容,如下示例:
#[derive(Debug)] struct Rectangle { width: u32, height: u32, } fn main() { let rect1 = Rectangle { width: 30, height: 50 }; println!("rect1 is {:?}", rect1); } // 输出: // rect1 is Rectangle { width: 30, height: 50 }