使用结构体组织相关联的数据
-
- 5.使用结构体组织相关关联的数据
-
- 1.结构体的定义和实例化
-
- 1.1定义结构体
- 1.2创建结构体的实例
- 1.3使用字段初始化简写语法
- 1.3使用结构体更新语法从其他实例创建实例
-
- 1.使用旧的实例创建新实例
- [2. \.\.语法创建实例(旧实例为基础)](#2. ..语法创建实例(旧实例为基础))
- 1.4使用没用命名字段的元组结构体来创建不同的类型
- 1.5没有任何字段的类党员结构体
- 2.结构体示例程序
-
- 2.1使用元组重构
- [2.2使用结构体重构: 赋予更多意义](#2.2使用结构体重构: 赋予更多意义)
- 2.3通过派生trait增加实用功能
- 3.方法语法
-
struct
或者structure
,是一个自定数据类型
,允许你包装
和命名
多个相关的值,从而形成一个有意义的组合
5.使用结构体组织相关关联的数据
1.结构体的定义和实例化
- 定义结构体,需要使用struct关键词并为整个结构体提供一个名字
- 结构体的名字需要描述它所组合的数据的意义
- 大括号中,定义每一部分数据的名字和类型,称为字段
1.1定义结构体
rust
struct User{
active: bool,
username: String,
email: String,
sign_in_count: u64,
}
1.2创建结构体的实例
rust
fn main(){
let mut userOne = User {
active: true,
username: String::from("张三"),
email: String::from("ghekswew@gmail.com"),
sign_in_count: 1,
};
println!("The userOne is email: {}",userOne.email);//ghekswew@gmail.com
// 结构体的实例是可变的,可以使用点号并为对应的字段赋值,以达到修改的目的
userOne.email = String::from("jkfhfh@gmail.com");
}
-
多个字段的修改
- 前提是整个实例必须是可变的,Rust并不允许只将某个字段标记为可变
rustfn build_user(email: String,username: String) -> User{ User{ active: true, username: username, email: email, sign_in_count: 1, } }
- 返回一个带有给定的
email
和用户名的User
实例
1.3使用字段初始化简写语法
参数名
和字段名
都完全相同,使用字段初始化简写语法
rust
//重写build_user方法
fn build_user(email: String,username: String)->User{
User{
active: true,
username,
email,
sign_in_count: 1,
}
}
1.3使用结构体更新语法从其他实例创建实例
1.使用旧的实例创建新实例
- 使用旧实例的大部分值但改变其部份值来创建一个新的结构体实例通常是很有用的
rust
let user2 = User {
active: user1.active,
username: user1.username,
email: String::from("ghescjsjs@gmail.com"),
sign_in_count: user1.sign_in_count,
};
2. ..语法创建实例(旧实例为基础)
..
语法指定了剩余未显示设置值的字段应有与给定实例对应字段相同的值
rust
let user3 = User {
email: String::from("hsxhsgwh@gmail.com"),
// 这里不能使用user1,因为user1的username字段中的String被移动到user2,user1的username中的String失效`在这里插入代码片`
..user2
};
1.4使用没用命名字段的元组结构体来创建不同的类型
- 可以定义与元组类似的结构体,称为元组构体
- 元组结构体有着结构体名称提供的含义,但没有具体的字段名,只有字段的类型
rust
struct Color(i32,i32,i32);
struct Point(i32,i32,i32);
fn main(){
let black = Color(0,0,0);
let origin = Point(0,0,0)
}
- 元组结构体实例类似于元组,
.
+索引
访问值等等
1.5没有任何字段的类党员结构体
- 定义一个没有任何字段的结构体,称为类单元结构体
rust
struct AlwaysEqual;
fn main(){
let subject = AlwaysEqual;
}
2.结构体示例程序
rust
fn main() {
let width = 30;
let height = 50;
println!(
"The area of the rectangle is {} square pixels.",
area(width, height)
);
}
fn area(width: u32, height: u32) -> u32 {
width * height
}
- 函数area两个参数的关联性没表现出来
2.1使用元组重构
- 元组帮助增加了一些结构性,并且只需传入一个参数,但是还是不明确
rust
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
}
2.2使用结构体重构: 赋予更多意义
rust
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
}
2.3通过派生trait增加实用功能
rust
#[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 }
/*
rect1 is Rectangle {
width: 30,
height: 50,
}
*/
//println!("rect1 is {:#?}", rect1);
/*
[src\main.rs:22] &rect1 = Rectangle {
width: 30,
height: 50,
}
*/
dbg!(&rect1);
}
dbg!
宏接收一个表达式的所有权(与println!
宏想法,后者接收的是引用)- 打印出代码中调用
dbg!
宏时所在文件和行号,以及该表达式的结果值,并返回该值的所有权
3.方法语法
- 方法 与函数 区别
- 都是使用
fn关键字
和名称声明
,可以拥有参数
和返回值
,同时包含在某处调用该方法时会执行的代码 - 方法与函数不同的 ,它们在结构体的上线文中被定义(或者是枚举或trait对象的上下文),并且它们
第一个参数总是self
,它代表调用该方法的结构体实例
- 都是使用
3.1定义方法
rust
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
};
println!(
"The area of the rectangle is {} square pixels.",
rect1.area()
);
}
- 为了使函数定义于
Rectangle
的上下文中,使用impl
块中的所有内容都将与Rectangle
类型相关联 - main中改为方法语法,使用实例调用
area
方法 - 方法语法获取一个实例并加上一个点号,后跟方法名 、圆括号 以及任何参数
- 在
area
的签名中,使用&self
来替代rectangle: &Rectangle
,&self
实际上是self: &self
的缩写
==========================================================
- 与字段同名的方法将被定义为只返回字段中的值,而不做其他事,这样的方法被称为
getters
- getters可以把字段变成私有的,当方法是公共的
rust
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
fn width(&self) -> bool {
self.width > 0
}
}
fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
};
println!(
"The area of the rectangle is {} square pixels.",
rect1.area()
);
println!("The width is gt 0:{}", rect1.width()); //true
}
3.2补充知识点(运算符到哪去了?)
1.在C/C++中
- 有两种不同的运算符来调用方法
.
直接在对象上调用方法- ->在一个对象的指针上调用方法,这时需要
先解引用
object -> something()
和(*object).something()
一样
2.在rust中
- rust并没有一个与
->
等效的运算符,相反,Rust有自动引用 和解引用的功能 - 以下两种等价
p1.distance(&p2)
和(&p1).distance(&p2)
3.3带有更多参数的方法
rust
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
fn width(&self) -> bool {
self.width > 0
}
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
};
let rect2 = Rectangle {
width: 10,
height: 40,
};
let rect3 = Rectangle {
width: 60,
height: 45,
};
println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2)); //true
println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3)); // false
println!(
"The area of the rectangle is {} square pixels.",
rect1.area()
);
println!("The width is gt 0:{}", rect1.width()); //true
}
3.4关联函数
- 所有在impl块中定义的函数被称为关联函数
- 可以定义不以
self
为第一参数的关联函数(不是方法),它们并不作用于一个结构体的实例 - 使用
结构体命名
和::
语法来调用这个关联函数
rust
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn square(size: u32) -> Self {
Self {
width: size,
height: size,
}
}
}
fn main() {
let sq = Rectangle::square(3);
println!("{}", sq.width); //3
}
3.5多个impl块
- 每个结构体都允许拥有多个
impl
块
rust
impl Rectangle{
fn area(&self) -> u32{
self.width * self.height
}
}
impl Rectangle{
fn can_hold(&self,other: &Rectangle)-> bool{
self.width > other.width && self.height > other.height
}
}