使用结构体组织相关联的数据(5)

使用结构体组织相关联的数据

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并不允许只将某个字段标记为可变
    rust 复制代码
    fn 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
	}

}
相关推荐
舒一笑15 分钟前
大模型时代的程序员成长悖论:如何在AI辅助下不失去竞争力
后端·程序员·掘金技术征文
lang2015092816 分钟前
Spring Boot优雅关闭全解析
java·spring boot·后端
小羊在睡觉1 小时前
golang定时器
开发语言·后端·golang
用户21411832636021 小时前
手把手教你在魔搭跑通 DeepSeek-OCR!光学压缩 + MoE 解码,97% 精度还省 10-20 倍 token
后端
追逐时光者1 小时前
一个基于 .NET 开源、功能强大的分布式微服务开发框架
后端·.net
刘一说2 小时前
Spring Boot 启动慢?启动过程深度解析与优化策略
java·spring boot·后端
壹佰大多2 小时前
【spring如何扫描一个路径下被注解修饰的类】
java·后端·spring
间彧2 小时前
Java双亲委派模型的具体实现原理是什么?
后端
间彧2 小时前
Java类的加载过程
后端
DokiDoki之父2 小时前
Spring—注解开发
java·后端·spring