简介
- 接上回书
什么是struct
- struct,是结构体,是一个自定义的数据类型,目的是关联相关不同变量。
定义struct
- 使用struct 关键字,并为整个struct命名。
- 在花括号内,为所有字段定义名称和类型。
- 使用struct 需要创建 struct 的实例
1、为每个字段制定具体值。
2、无需按声明顺序制定。
- 获取struct 的值,通过点标记法即可 struct.filed_name
- 特别需要注意如果 struct 声明为可变的那么实例中的所有字段都是可变的。
- 举例:
fn main() {
struct Employee {
username: String,
age: i16,
email: String,
}
let emp = Employee {
username: String::from("LinHai."),
age: 39i16,
email: String::from("[email protected]"),
};
println!("Winer is : {} {} {}", emp.username, emp.age, emp.email);
}
- 字段初始化简写,当字段名与字段值的变量名称相同时可以使用简写方式,例如:(注意username、age变量的给值方法)
fn main() {
struct Employee {
username: String,
age: i16,
email: String,
}
let username = String::from("linhai");
let age:i16 = 39;
let emp = Employee {
username, // 如果变量名称与结构定义的变量名相同则可以直接赋值
age, // 如果变量名称与结构定义的变量名相同则可以直接赋值
email: String::from("[email protected]"),
};
println!("Winer is : {} {} {}", emp.username, emp.age, emp.email);
}
- 还有一种比较特殊的 struct 的更新语法,可以基于某个已有的结构实例初始化新的对象,如下例子中注意 ..emp 的用法:
fn main() {
struct Employee {
username: String,
age: i16,
email: String,
}
let username = String::from("linhai");
let age:i16 = 39;
// 定义基础实例对象
let emp = Employee {
username, // 如果变量名称与结构定义的变量名相同则可以直接赋值
age, // 如果变量名称与结构定义的变量名相同则可以直接赋值
email: String::from("[email protected]"),
};
let mut emp_child = Employee {
username: String::from("林巍"),
..emp // 这种拓展语法可以基于某个结构建立结构
};
// 修改年龄
emp_child.age = 3;
println!("Winer is : {} {} {}", emp_child.username, emp_child.age, emp_child.email);
}
Tuple struct
- 这是一个简化版的 struct,具体形式大致如下:
struct Color(i32,i32,i32);
struct Point(i32,i32);
let black = Color(0,0,0);
let origin = Point(0,0,0);
- 还有一种更特殊的叫做 Unit-Like Struct 比如
struct Man {};
数据的所有权
-
你会发现如果定一个变量,是String类型,但是随着赋值所有权会转移到结构中,之后在使用就会出错,比如:
- 具体的解决需要引入声明周期的概念,稍后再讲。
一个具体的实例
- 接下来将根据这个程序进行改写。
fn main() {
// 初始化结构
let rec = Rectangle {
width: 30,
height: 50,
};
let result = area(&rec);
println!("矩形:{:?},的面积是:{}", rec, result);
}
// 定一个个矩形结构
#[derive(Debug)]
struct Rectangle {
width: i32,
height: i32,
}
// 定一个区域函数
fn area(rectangle:&Rectangle) -> i32{
rectangle.width * rectangle.height
}
Struct 的方法
- 方法和函数类似,通过fn关键字定义,名称、参数和返回值。
- 方法与函数不同的地方:
1、方法是在struct(enum、trait对象)的上下文中定义的。
2、方法的第一个参数是self,self指向被调用的struct 实例。
3、方法在 impl (implement)块中定义的` impl StructName {}`
4、方法的第一个参数可以使 &self,也可以获得其所有权或可变借用,和其他参数一样。
- 改进上面的实例,主要是把 area 方法整合到 struct 中,这样整体结构更好:
fn main() {
// 初始化结构
let rec = Rectangle {
width: 30,
height: 50,
};
let result = rec.area(); // 改变了计算形式。
println!("矩形:{:?},的面积是:{}", rec, result);
}
// 定一个个矩形结构
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
// 这个就是给Struct 加方法的方式
impl Rectangle {
// 定一个区域函数(从外面挪到块里面)
fn area(&self) -> u32{
self.width * self.height
}
}
- 方法调用的是的特别说明
/*
C/C++中: object->something() 等于 (*object).something() 也就是解构指针,Rust并不需要这样,Rust会自动引用或解引用。
在调用方法时,Rust根据情况自动添加 &、&mut 或 * ,以便 object 可以匹配方法的签名。
*/
p1.distance(&p2);
// 等于
(&p1).distance(&p2);
- Struct 后面还可以跟随多个不同参数:
fn main() {
// 初始化结构
let rec = Rectangle {
width: 30,
height: 50,
};
let rec2 = Rectangle {
width: 20,
height: 30,
};
let rec3 = Rectangle {
width: 70,
height: 30,
};
let result = rec.area();
println!("矩形:{:?},的面积是:{}", rec, result);
println!("rec 能放下 rec2 ? {}", rec.can_hold(&rec2) );
println!("rec 能放下 rec3 ? {}", rec.can_hold(&rec3) );
}
// 定一个个矩形结构
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// 定一个区域函数
fn area(&self) -> u32{
self.width * self.height
}
fn can_hold(&self, rec: &Rectangle) -> bool {
self.width > rec.width && self.height > rec.height
}
}
关联函数(类似于静态方法)
- 可以在impl 块中定义一个不以 self 作为第一个参数的函数,这种形式叫做关联函数,调用方式类似 String::from()
- 关联函数通常用于构造器,举例:
fn main() {
// 初始化结构
let width = 60u32;
let square = Rectangle::create_square(width);
let result = square.area();
println!("矩形:{:?},的面积是:{}", square, result);
println!("开始定义的变量 width = {} 的所有权被交回来了因此并不会消失", width);
}
// 定一个个矩形结构
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// 定一个区域函数
fn area(&self) -> u32{
self.width * self.height
}
// 创建一个正方形,注意这里的参数 width 传递的是所有权
fn create_square(width: u32) -> Rectangle {
// 初始化后实际上把所有权返回了。
Rectangle {
width,
height: width,
}
}
}
Struct 的智能指针 Box
参考文档:https://rustcc.cn/article?id=76e5f3fb-20b9-48c9-8fc6-a0aad40ced8c
智能指针
1、智能指针的概念起源于C++,智能指针是一类数据结构,他们的表现类似指针,但是拥有额外的元数据和功能。
2、在Rust中,引用和智能指针的一个的区别是引用是一类只借用数据的指针;相反,在大部分情况下,智能指针拥有他们指向的数据。Rust标准库中不同的智能指针提供了比引用更丰富的功能:
------------------
Box,用于在堆上分配数据。
Rc,一个引用计数类型,其数据可以有多个所有者。
Ref 和 RefMut,通过RefCell访问,一个在运行时而不是在编译时执行借用规则的类型。
- 智能指针Box
1、在Rust中,所有值默认都是栈上分配。
2、通过创建Box,可以把值装箱,使它在堆上分配。
3、Box类型是一个智能指针,因为它实现了Dereftrait,它允许Box值被当作引用对待。
4、当Box值离开作用域时,由于它实现了Droptrait,首先删除其指向的堆数据,然后删除自身。
- Box
的举例,如果一个类型指向他自己就可以通过Box 来实现,比如一个树的节点表示
#[derive(Debug)]
struct TreeNode {
data :i32,
left_node : Box,
right_node : Box,
}
结束
- 感谢阅读。