定义结构体并实例化
类似面向对象编程的类语法
rust
struct Student {
stu_no: i32,
name: String,
register_at: String
}
fn main() {
let tom = Student {
stu_no: 1001,
name: String::from("tom"),
register_at: String::from("2020-01-11"),
};
println!("stu_no: {}", tom.stu_no);
println!("name: {}", tom.name);
println!("register: {}", tom.register_at);
}字段初始化的简写语法
类似js对象的简写语法,key和value变量同名可以省略
rust
struct Student {
stu_no: i32,
name: String,
register_at: String
}
fn build_student(id:i32, name:String, register_at:String) -> Student {
Student {
stu_no: id, // 不同名是不能缩写语法的
name,
register_at,
}
}
fn main() {
let name = String::from("jerry");
let reg_at = String::from("2022-11-21");
let jerry = build_student(1002, name, reg_at);
println!("stu_no: {}", jerry.stu_no);
println!("name: {}", jerry.name);
println!("register: {}", jerry.register_at);
}使用结构体更新语法从其他实例创建实例
这个功能类似js的延展符的功能 {...obj1, ...obj2}
rust
struct User {
id: i32,
name: String,
password: String,
is_actived: bool,
is_banned: bool,
is_real_auth: bool,
}
fn main() {
let tom = User {
id: 1001,
name: String::from("tom"),
password: String::from("123456"),
is_actived: true,
is_banned: false,
is_real_auth: true,
};
let jerry = User {
id: 1002,
name: String::from("jerry"),
..tom // 不会覆盖已有的字段
};
println!("jerry.id :{}", jerry.id);
println!("jerry.name :{}", jerry.name);
println!("jerry.password :{}", jerry.password);
println!("jerry.is_actived:{}", jerry.is_actived);
println!("jerry.is_banned :{}", jerry.is_banned);
println!("jerry.is_banned :{}", jerry.is_real_auth);
}定义类元组结构体
rust
// 类似元组一样的结构体
struct IpAddrV4(u8, u8, u8, u8);
impl IpAddrV4 {
fn to_addr_string(&self) -> String {
let mut addr_str = String::new();
addr_str += self.0.to_string().as_str();
addr_str += ".";
addr_str += self.1.to_string().as_str();
addr_str += ".";
addr_str += self.2.to_string().as_str();
addr_str += ".";
addr_str += self.3.to_string().as_str();
addr_str
}
}
fn main() {
let ip = IpAddrV4(192, 168, 11, 255);
println!("ip: {}", ip.to_addr_string());
}使用#[derive(Debug)]
- 不用管 trait 和 #[derive(debug)] 是什么, 后续都会学
- 只需要知道, 在结构体上加上这个就可以使用
println!这个宏来输出, 以便查看信息
rust
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let rect = Rectangle {
width: 10,
height: 10
};
println!("rect width : {}", rect.width);
println!("rect height: {}", rect.height);
// 如果没有加上 #[derive] 无法直接输出
println!("rect: {:?}", rect);
// 也可以使用dbg宏
dbg!(rect);
}实例方法
类似面向对象编程的定义方法
rust
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn get_area(&self) -> u32 {
self.width * self.height
}
// 多个参数 &Self 就是 &Rectangle 的意思,
// 只不过 Self 是关键字代表当前的 struct
fn can_hold(&self, other_rect: &Self) -> bool {
self.width >= other_rect.width && self.height >= other_rect.height
}
}
fn main() {
let rect = Rectangle {
width: 10,
height: 10
};
let rect2 = Rectangle {
width: 20,
height: 20,
};
println!("rect area: {}", rect.get_area()); // 100
println!("rect2 area: {}", rect2.get_area()); // 100
println!("rect2 can hold rect? {}", rect2.can_hold(&rect));
}关联函数
关联函数只是返回值是 Rectangle, 但第一个参数并不是 &self 所以不能称之为方法
比如之前一直使用的 String::from 就是一个关联函数, 他的第一个参数并不是 &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 square = Rectangle::square(10);
dbg!(square);
}多个 impl
一个结构体可以有多个 impl 块
rust
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
// 放实例方法
impl Rectangle {
fn get_area(&self) -> u32 {
self.width * self.height
}
fn can_hold(&self, other_rect: &Self) -> bool {
self.width >= other_rect.width && self.height >= other_rect.height
}
}
// 放关联函数
impl Rectangle {
fn square(size: u32) -> Self {
Self {
width: size,
height: size,
}
}
}
fn main() {
let square = Rectangle::square(10);
dbg!(square);
}self 和 Self
可以这样理解 self 代表当前实例, 作用类似 Java 的 this 关键字
而 Self 代表当前 impl 的 struct, 如: impl X Self 就代表 X
小例子: 使用结构体语法改造猜数字游戏代码
rust
use rand::random_range;
use std::cmp::Ordering;
use std::io;
// 将控制游戏逻辑的字段放到一个结构体中
struct GuessNumberConfig {
is_debug_mode: bool,
anwser_number: u32,
input_content: String,
guess_chances: u32,
min_number: u32,
max_number: u32,
}
// 实现一些配置字段的方法
impl GuessNumberConfig {
fn new() -> Self {
Self {
is_debug_mode: false,
anwser_number: 0,
input_content: String::new(),
guess_chances: 1,
min_number: 1,
max_number: 10,
}
}
// 设置调试模式
fn set_debug_mode(&mut self, is_debug_mode: bool) {
self.is_debug_mode = is_debug_mode;
}
// 设置答案随机数
fn set_anwser_number(&mut self) {
self.anwser_number = random_range(self.min_number..=self.max_number);
}
// 设置输入内容
fn set_input_content(&mut self, input_str: String) {
self.input_content = input_str;
}
// 解析输入内容为数字
fn parse_input_content(&self) -> u32 {
let num: u32 = self
.input_content
.clone()
.trim()
.parse()
.expect("failed to parse input content");
num
}
// 设置猜测机会
fn set_guess_chances(&mut self, guess_chances: u32) {
self.guess_chances = guess_chances;
}
// 是否还有猜测机会
fn has_guess_chances(&self) -> bool {
self.guess_chances > 0
}
// 减少猜测机会
fn decrease_guess_chances(&mut self) {
self.set_guess_chances(self.guess_chances - 1);
}
// 设置答案随机数最小数字
fn set_min_number(&mut self, min_num: u32) {
self.min_number = min_num;
}
// 设置答案随机数最大数字
fn set_max_number(&mut self, max_num: u32) {
self.max_number = max_num;
}
}
fn main() {
println!("=== 猜数字游戏 ===");
let mut config = GuessNumberConfig::new();
config.set_debug_mode(true);
config.set_guess_chances(3);
config.set_anwser_number();
config.set_min_number(1);
config.set_max_number(9);
// 是否输出调试信息(告知答案)
if config.is_debug_mode {
println!("答案数字是:{}", config.anwser_number);
}
loop {
// 判断猜测机会
if !config.has_guess_chances() {
println!("机会用完了, 游戏结束,答案是:{}", config.anwser_number);
break;
}
// 输出提示信息
print!(
"请输入一个数字({}-{}):",
config.min_number, config.max_number
);
println!(",你还有{}次机会", config.guess_chances);
// 获取用户输入并设置到结构体字段中
let mut input_str = String::new();
io::stdin().read_line(&mut input_str).expect("fail to read");
config.set_input_content(input_str);
// 解析输入内容为数字并判断大小
let input_num = config.parse_input_content();
match config.anwser_number.cmp(&input_num) {
Ordering::Less => println!("你输入的数字太小了"),
Ordering::Greater => println!("你输入的数字太大了"),
Ordering::Equal => {
println!("恭喜你猜对了, 你赢了 ^_^ ");
break;
}
}
// 设置猜测机会(减少一次)
config.decrease_guess_chances();
}
}