《Rust权威指南》 第5章 使用结构体组织相关联的数据

本文介绍了Rust中如何定义和使用结构体,包括通过struct关键字声明结构体,简化字段初始化,结构体更新语法,以及使用元组结构体和空结构体。此外,还讲解了如何通过派生trait如Debug增加结构体的功能,并展示了如何定义和调用结构体的方法。
摘要由CSDN通过智能技术生成

定义并实例化结构体

使用struct,像其它任何语言一样,声明所有数据的类型和名称(这里你注意到,声明的最后也有一个逗号)

strcut User {
	username:String,
	email:String,
	sign_in_count:u64,
	active:bool,
}

创建一个结构体实例时,通过下面的语法进行创建。每一项都是数据名称:实例数据。注意可以不按照声明顺序排列:

let mut user1 = User {
	username:String::from("a@xx.com"),
	email:String::from("xx"),
	sign_in_count:1,
	active:true,
};

访问结构体的成员时,使用.。就如在其它任何语言中一样

user1.active = false;

下面提供几种快捷的初始化实例的方法

在变量名与字段名相同时使用简化版字段初始化方法

例子:

fn build_user(email:String,username:String) -> User {
	User {
		email,
		username,
		avtive:true,
		sign_in_count:1,
	}
}

由于字段名email和我们用于初始化该字段的变量名email相同,我们可以将email:email简写成email

使用结构体更新语法根据其它实例创建新实例

例子:

let user2 = User {
	username:String::from("a@xx.com"),
	email:String::from("xx"),
	..user1
};

上面等同于使用以下代码,根据user1的数据创建user2

let user2 = User {
	username:String::from("a@xx.com"),
	email:String::from("xx"),
	sign_in_count:user1.sign_in_count,
	active:user1.active,
};

使用不需要对字段命名的元组结构体来创建不同类型

一般来说,当你想要给元组赋予名字,并使其有区别于其它有同样定义的元组时,使用元组结构体。其语法看上去就是为元组命了个名

struct Color(i32,i32,i32);
let black = Color(0,0,0);

元组结构体实例的行为与元组完全一致

没有任何字段的结构体

允许创建不包含任何字段的空结构体,通常用于在某些类型上实现trait,却不需要在该类型上存储数据时

使用结构体

我们以一个长方形结构体为例

struct Rectangle {
	width:u32,
	height:u32,
}

fn main {
	let rect1 = Rectangle {width:30,height:20};
}

通过派生trait增加实用功能

假如我们尝试

println!("rect1 is {}",rect1);

会报错

  |
8 |     println!("rect1 is {}",rect1);
  |                            ^^^^^ `Rectangle` cannot be formatted with the default formatter
  |
  = help: the trait `std::fmt::Display` is not implemented for `Rectangle`
  = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
  = 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指示我们,实现std::fmt::Display,这个trait才可以。
后面又建议我们使用{:?},这是使用Debug的格式化输出。我们改一下:

println!("rect1 is {:?}",rect1);

又报错了

  |
8 |     println!("rect1 is {:?}",rect1);
  |                              ^^^^^ `Rectangle` cannot be formatted using `{:?}`
  |
  = help: the trait `Debug` is not implemented for `Rectangle`
  = note: add `#[derive(Debug)]` to `Rectangle` or manually `impl Debug for Rectangle`
  = 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 `Rectangle` with `#[derive(Debug)]`
  |
1 | #[derive(Debug)]
  |

我们直接听从意见,在结构体顶以前加#[derive(Debug)]注解,修改程序为

#[derive(Debug)]
struct Rectangle {
	width:u32,
	height:u32,
}

fn main() {
	let rect1 = Rectangle {width:30,height:20};
    println!("rect1 is {:?}",rect1);
}

最终程序会打印:rect1 is Rectangle { width: 30, height: 20 },这可以用于调试

方法

方法与函数基本上类似,区别在于:

  • 方法定义在某个结构体的上下文中
  • 方法的第一个参数永远是self

定义方法

给我们的长方体定义一个计算面积的方法

impl Rectangle {
    fn area(&self) -> u32 {
        self.width*self.height
    }
}
  • 方法的定义位于impl块中
    • 当然,每个结构体都可以拥有多个impl块
  • 第一个参数是&self
    • 正是因为位于impl Rectangle { }中,&self才能被推导为rectangle:&Rectangle
    • 若方法要获得所有权,使用self;若要修改调用者的数据,使用&mut self;不过我们这里只需要读取,所以使用了&self
  • 使用方法时,rect1.area()。此时rect1传递给参数&self

关联函数

函数与结构体直接关联,定义在impl块中,但是不接受self作为参数

impl Rectangle {
    fn square(size:u32) -> Rectangle {
        Rectangle {width:size,height:size}
    }
}

使用时,在类型后面加::。比如let sq = Retangle::square(3);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值