结构体

结构体允许我们命名多个相关的值并组合在一起。 结构与元组相似,不同的是结构体需要为每个数据赋予名字来表达它们的意义,结构体正是因为这些名字变得比元素要更加灵活。

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

创建实例之后,可以通过点号来访问结构体的特定字段。

let mut user1 = User {
	username: String::from("someusername123"),
	email: String::from("[email protected]"),
	sign_in_count: 1,
	active: true,
};
 
user1.email = String::from("[email protected]");

一旦实例可变,那么实例中的所有字段都是可变的,不允许部分字段可变

当变量名与字段名一致的时候,可以使用字段初始化简写:

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

还可以根据一个实例来创建一个新实例:

let user2 = User {
	email: String::from("[email protected]"),
	username: String::from("anotherusername"),
	..user1 // 这里的双点号表示剩下还没有显式赋值的都与user1的值相同。
};

元组结构体

使用一种类似于元组的方式定义结构体,这种结构体就叫做元组结构体。其实就是为元组取名,但是就算元组结构体定义一样,名字不同也是不同的类型

定义的每一个结构体都拥有自己的类型,即便结构体中的字段拥有完全相同的类型.

例如:

struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
 
// 这里black和origin是不同的类型
let black = Color(0,0,0);
let origin = Point(0,0,0);

空结构体

没有任何字段的结构体,与空元组()十分相似,被称为空结构体。

结构体数据的所有权

上面的结构体示例中,使用自持有所有权的String类型而不是&str,因为希望这个结构体具有自身全部数据的所有权,其实也可以在结构体中存储指向其它数据的引用,但是需要用Rust中独有的生命周期来解决这个问题I。

通过trait增加实用功能

先创建一个类型:

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

尝试打印Rectangle实例的信息,在println!宏中如果格式化动词为{},需要类型实现std::fmt::Display trait,如果格式化动词为{:?}或者{:#?},需要实现std::fmt::Debug trait。

通过添加#[derive(Debug)]来实现std::fmt::Debug trait

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

Rust提供了很多可以通过derive注解来派生trait。

方法

方法的概念与其它面向对象的语言中对象的方法一样。 方法总是定义在某个结构体中,第一个参数永远都是self

可以为上面的Rectangle类型实例实现一个获取面积的area的方法:

impl Rectangle {
    fn area(self) -> u32 {
        self.width * self.height
    }
}

调用方法为:

rect.area()
// 实际上也是调用一个函数 area(rect)

因为方法的第一个参数是self,会发生移动,所以如果希望调用完方法后仍然能够继续需要变量,方法的参数类型需要修改为&self,如果方法中还会修改实例的数据,那么类型为&mut self

自动引用和解引用

在实例调用方法的时候,我们可以直接使用点来调用方法,而不需要在于方法的第一个参数是self还是&self&mut self。 Rust会自动为调用者添加&, &mut, *,让其符合方法的签名。

关联函数

关联函数是在impl块中定义的不需要接收self作为参数的函数,这类函数与结构体相关,称为关联函数。在面向对象的语言中相当于类的静态方法

例如为一个类型定义一个New函数:

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

多个impl块

每个结构体可以拥有多个impl块。 可以对方法进行分类,写在不同的impl中,便于理解。后面实现trait也经常需要多个impl块。


tags: Rust数据类型 自定义数据类型