复合类型
复合类型
结构体 (Struct)
三种类型
结构体( struct )可以由各种不同类型组成。使用 struct 关键字来创建。struct 是 structure 的缩写。 结构体可以作为另一个结构体的字段。结构体是可以嵌套的。
有三种类型:
// 1. 经典的 C 语言风格结构体(C struct)
struct 结构体名称 {
...
}
// 2. 单元结构体(unit struct),不带字段,在泛型中很有用。
struct Unit;
// 3. 元组结构体(tuple struct),事实上就是具名元组而已。
struct Pair(String, i32);
下面主要以C风格结构体为例
(1) C风格结构体
定义
struct 结构体名称 {
字段1: 数据类型,
字段2: 数据类型,
...
}
创建、初始化
其实就是对 结构体中的各个元素进行赋值
let 实例名称 = 结构体名称 {
field1: value1,
field2: value2
...
};
示例
#[derive(Debug)]
struct Study {
name: String,
target: String,
spend: i32,
}
fn main() {
let s = Study {
name: String::from("从0到Go语言微服务架构师"),
target: String::from("全面掌握Go语言微服务落地,代码级一次性解决微服务和分布式系统。"),
spend: 3,
};
println!("{:?}", s);
}
// 输出
Study { name: "从0到Go语言微服务架构师", target: "全面掌握Go语言微服务落地,代码级一次性解决微服务和分布式系统。", spend: 3 }
访问实例属性
实例名称.属性
示例
println!("{}", s.name); // 输出 从0到Go语言微服务架构师
修改结构体实例
结构体实例默认是不可修改的,如果想修改结构体实例,声明时使用mut关键字。
let mut s2 = Study {
name: String::from("从0到Go语言微服务架构师"),
target: String::from("全面掌握Go语言微服务落地,代码级一次性解决微服务和分布式系统。"),
spend: 3,
};
s2.spend = 7; // 修改
println!("{:?}", s2);
// 输出
Study { name: "从0到Go语言微服务架构师", target: "全面掌握Go语言微服务落地,代码级一次性解决微服务和分布式系统。", spend: 7 }
结构体做参数
fn show(s: Study) {
println!(
"name is :{} target is {} spend is{}", s.name, s.target, s.spend
);
}
结构体作为返回值
fn get_instance(name: String, target: String, spend: i32) -> Study {
return Study {
name,
target,
spend,
};
}
let s3 = get_instance(
String::from("Go语言极简一本通"),
String::from("学习Go语言语法,并且完成一个单体服务"),
5,
);
println!("{:?}", s3);
// 输出:
Study { name: "Go语言极简一本通", target: "学习Go语言语法,并且完成一个单体服务", spend: 5 }
结构体方法
普通方法
方法(method)是依附于对象的函数。这些方法通过关键字 self 来访问对象中的数据和其他。方法在 impl 代码块中定义。
与函数的区别
- 函数:可以直接调用,同一个程序不能出现 2 个相同的函数签名的函数,应为函数不归属任何 owner。
- 方法:归属某一个 owner,不同的 owner 可以有相同的方法签名。
impl 结构体 { // "impl" 是 "implement" 的缩写。意思是 “实现”的意思。
fn 方法名(&self, 参数列表) 返回值 { // "self" 是 "自己" 的意思。
// &self 表示当前结构体的实例。&self 也是结构体普通方法固定的第一个参数,其他参数可选。
// 方法体
}
}
结构体方法的作用域仅限于结构体内部。
impl Study {
fn get_spend(&self) -> i32 {
return self.spend;
}
}
println!("spend {}", s3.get_spend());
// 输出 spend 5
静态方法
// 定义
fn 方法名(参数: 数据类型, ...) -> 返回值类型 { // 与普通方法的区别:没有 &self 作为第一个参数
// 方法体
}
// 调用
结构体名称::方法名(参数列表)
示例
impl Study {
...
fn get_instance_another(name: String, target: String, spend: i32) -> Study {
return Study {
name,
target,
spend,
};
}
}
let s4 = Study::get_instance_another(
String::from("Go语言极简一本通"),
String::from("学习Go语言语法,并且完成一个单体服务"),
5,
);
(2) 单元结构体 (unit type)
unit type 是一个类型,有且仅有一个值:
(),单元类型()类似 c/c++/java 语言中的 void
- 当一个函数并不需要返回值的时候,其他语言返回void
- rust 则返回()
但语法层面上,void 仅仅只是一个类型,该类型没有任何值;而单元类型()既是一个类型,同时又是该类型的值。
(3) 元祖结构体
实例化
let pair = (String::from("从0到Go语言微服务架构师"), 1);
访问
访问元组结构体的字段
println!("pair 包含 {:?} and {:?}", pair.0, pair.1);
// 输出:
pair 包含"从0到Go语言微服务架构师" and 1
解构
解构一个元组结构体
let (study, spend) = pair;
println!("pair 包含 {:?} and {:?}", study, spend);
// 输出:内容同上
pair 包含"从0到Go语言微服务架构师" and 1
枚举 (Enum)
枚举 enum 关键字允许创建一个从数个不同取值中选其一的枚举类型(enumeration)。任何一个在 struct 中合法的取值在 enum 中也合法。
在日常生活中很常见。比如:1 年有 12 个月,1 周有 7 天。
枚举的定义
enum 枚举名称{
variant1,
variant2,
...
}
使用枚举
枚举名称::variant
示例
#[derive(Debug)] // #[derive(Debug)] 注解的作用,就是让 派生自Debug。
enum RoadMap {
Go语言极简一本通,
Go语言微服务架构核心22讲,
从0到Go语言微服务架构师,
}
fn main() {
let level = RoadMap::从0到Go语言微服务架构师;
println!("level---{:?}", level);
}
Option 枚举
enum Option<T> {
Some(T), // 用于返回一个值
None // 用于返回 null,用None来代替。
}
Option 枚举经常用在函数中的返回值,它可以表示有返回值,也可以用于表示没有返回值。如果有返回值。
可以使用返回 Some(data),如果函数没有返回值,可以返回 None。
fn getDiscount(price: i32) -> Option<bool> {
if price > 100 {
Some(true)
} else {
None
}
}
let p = 666; // 输出 Some(true)
// let p=6; // 输出 None
let result = getDiscount(p);
println!("{:?}", result)
match 语句
判断一个枚举变量的值,唯一操作符就是 match。
fn print_road_map(r:RoadMap){
match r {
RoadMap::Go语言极简一本通=>{
println!("Go语言极简一本通");
},
RoadMap::Go语言微服务架构核心22讲=>{
println!("Go语言微服务架构核心22讲");
},
RoadMap::从0到Go语言微服务架构师=>{
println!("从0到Go语言微服务架构师");
}
}
}
print_road_map(RoadMap::Go语言极简一本通); // 输出 Go语言极简一本通
print_road_map(RoadMap::Go语言微服务架构核心22讲); // 输出 Go语言微服务架构核心22讲
print_road_map(RoadMap::从0到Go语言微服务架构师); // 输出 从0到Go语言微服务架构师
带数据类型的枚举
(不知道能怎么用)
enum 枚举名称 {
variant1(数据类型1),
variant2(数据类型2),
...
}
示例
#[derive(Debug)]
enum StudyRoadMap {
Name(String),
}
let level3 = StudyRoadMap::Name(String::from("从0到Go语言微服务架构师"));
match level3 {
StudyRoadMap::Name(val) => {
println!("{:?}", val);
}
}
//输出 "从0到Go语言微服务架构师"
集合 (Collections) - 未
Rust 语言标准库提供了通用的数据结构的实现。包括:
- 向量 (Vector)
- 哈希表( HashMap )
- 哈希集合( HashSet )
向量 (Vector)
Rust 在标准库中定义了结构体 Vec 用于表示一个向量。向量和数组很相似,只是数组长度是编译时就确定了,定义后就不能改变了,那要么改数组,让他支持可变长度,显然 Rust 没有这么做,它用向量这个数据结构,也是在内存中开辟一段连续的内存空间来存储元素。
特点:
- 向量中的元素都是相同类型元素的集合。
- 长度可变,运行时可以增加和减少。
- 使用索引查找元素。(索引从 0 开始)
- 添加元素时,添加到向量尾部。
- 向量的内存在堆上,长度可动态变化。
创建向量
new() 静态方法用于创建一个结构体 Vec 的实例。
let mut 向量的变量名称 = Vec::new();
vec!() 宏来简化向量的创建。
let 向量的变量名称 = vec![val1,val2,...]
向量的使用方法
方法 | 说明 |
---|---|
new() | 创建一个空的向量的实例 |
push() | 将某个值 T 添加到向量的末尾 |
remove() | 删除并返回指定的下标元素 |
contains() | 判断向量是否包含某个值 |
len() | 返回向量中的元素个数 |
let mut v = Vec::new();//调用 Vec 结构的 new() 静态方法来创建向量。
v.push("Go语言极简一本通"); //通过push方法添加元素数据。并且追加到向量尾部。
v.push("Go语言微服务核心架构22讲");
v.push("从0到Go语言微服务架构师");
println!("{:?}",v);
println!("len :{}",v.len()); // 通过len方法获取向量中的元素个数。
let mut v2 = vec!["Go语言极简一本通","Go语言微服务核心架构22讲","从0到Go语言微服务架构师"];
// 通过vect!宏创建向量时,向量的数据类型由第一个元素自动推断出来。
println!("{:?}",v2);
let x=v2.remove(0);
// remove()方法移除并返回向量中指定的下标索引处的元素,将其后面的所有元素移到向左移动一位。
println!("{}",x); //输出 Go语言极简一本通
println!("{:?}",v2);//输出 ["Go语言微服务核心架构22讲", "从0到Go语言微服务架构师"]
//contains() 用于判断向量是否包含某个值。如果值在向量中存在则返回 true,否则返回 false。
if v.contains(&"从0到Go语言微服务架构师"){
println!("找到了")
}
//访问向量中的某个元素,使用索引
let y = v[0];
println!("{}",y); //输出 Go语言极简一本通
//遍历向量
for item in v {
println!("充电项目: {}", item);
}
//输出
充电项目: Go语言极简一本通
充电项目: Go语言微服务核心架构22讲
充电项目: 从0到Go语言微服务架构师
哈希表 (HashMap)
HashMap 就是键值对集合。键是不能重复的,值是可以重复的。
使用 HashMap 结构体之前需要显式导入 std::collections 模块。
创建 HashMap
使用 new()方法来创建。
let mut 变量名称 = HashMap::new();
这个哈希表只有当我们添加了元素之后才能正常使用。因为现在还没指定的数据类型。
方法 | 说明 |
---|---|
insert() | 插入/更新一个键值对到哈希表中,如果数据已经存在则返回旧值,如果不存在则返回 None |
len() | 返回哈希表中键值对的个数 |
get() | 根据键从哈希表中获取相应的值 |
iter() | 返回哈希表键值对的无序迭代器,迭代器元素类型为 (&’a K, &’a V) |
contains_key | 如果哈希表中存在指定的键则返回 true 否则返回 false |
remove() | 从哈希表中删除并返回指定的键值对 |
use std::collections::HashMap;
let mut process = HashMap::new();
process.insert("Go语言极简一本通", 1);
process.insert("Go语言微服务核心架构22讲", 2);
process.insert("从0到Go语言微服务架构师", 3);
println!("{:?}", process);
//输出 {"Go语言极简一本通": 1, "Go语言微服务核心架构22讲": 2, "从0到Go语言微服务架构师": 3}
println!("len {}",menu.len());
//输出 3
// get() 方法用于根据键从哈希表中获取相应的值。
match process.get(&"从0到Go语言微服务架构师"){
Some(v)=>{
println!("HashMap v:{}", v);
}
None=>{
println!("找不到");
}
}
//输出 HashMap v:3
//迭代哈希表 iter()
for (k, v) in process.iter() {
println!("k: {} v: {}", k, v);
}
//输出
k: Go语言微服务核心架构22讲 v: 2
k: 从0到Go语言微服务架构师 v: 3
k: Go语言极简一本通 v: 1
// contains_key() 方法用于判断哈希表中是否包含指定的 键值对。如果包含指定的键,那么会返回相应的值的引用,否则返回 None。
if process.contains_key(&"Go语言极简一本通") {
println!("找到了");
}
//输出 找到了
// remove() 用于从哈希表中删除指定的键值对。如果键值对存在则返回删除的键值对,返回的数据格式为 (&'a K, &'a V)。如果键值对不存在则返回 None
let x=process.remove(&"Go语言极简一本通");
println!("{:?}",x);
println!("{:?}",process);
//输出
Some(1)
{"Go语言微服务核心架构22讲": 2, "从0到Go语言微服务架构师": 3}
哈希集合 (HashSet)
Hashset 是相同数据类型的集合,它是没有重复值的。如果集合中已经存在相同的值,则会插入失败。
创建 Hashset
let mut 变量名称 = HashSet::new();
常用方法如下
方法 描述
insert() 插入一个值到集合中 如果集合已经存在值则插入失败
len() 返回集合中的元素个数
get() 根据指定的值获取集合中相应值的一个引用
iter() 返回集合中所有元素组成的无序迭代器 迭代器元素的类型为 &'a T
contains_key 判断集合是否包含指定的值
remove() 从结合中删除指定的值
insert() 用于插入一个值到集合中。
let mut studySet = HashSet::new();
studySet.insert("Go语言极简一本通");
studySet.insert("Go语言微服务核心架构22讲");
studySet.insert("从0到Go语言微服务架构师");
println!("{:?}", studySet);
//输出 {"从0到Go语言微服务架构师", "Go语言微服务核心架构22讲", "Go语言极简一本通"}
studySet.insert("从0到Go语言微服务架构师");
println!("{:?}", studySet);
//输出 {"从0到Go语言微服务架构师", "Go语言微服务核心架构22讲", "Go语言极简一本通"}
len() 方法集合中元素的个数。
println!("len:{}",studySet.len());//输出 len:3
iter() 方法用于返回集合中所有元素组成的无序迭代器。
for item in studySet.iter(){
println!("hashSet-充电项目: {}", item);
}
//输出
hashSet-充电项目: Go语言极简一本通
hashSet-充电项目: Go语言微服务核心架构22讲
hashSet-充电项目: 从0到Go语言微服务架构师
get() 方法用于获取集合中指定值的一个引用。
match studySet.get("从0到Go语言微服务架构师") {
None => {
println!("没找到");
}
Some(data) => {
println!("studySet中找到:{}",data);
}
}
//输出 studySet中找到:从0到Go语言微服务架构师
contains() 方法用于判断集合是否包含指定的值。
if studySet.contains("Go语言微服务核心架构22讲"){
println!("包含 Go语言微服务核心架构22讲")
}
//输出 包含 Go语言微服务核心架构22讲
remove() 方法用于从集合中删除指定的值。如果该值在集合中,则返回 true,如果不存在则返回 false。
studySet.remove("Go语言极简一本通");
println!("{:?}",studySet);//输出 {"Go语言微服务核心架构22讲", "从0到Go语言微服务架构师"}
studySet.remove("golang");
println!("{:?}",studySet);//输出 {"Go语言微服务核心架构22讲", "从0到Go语言微服务架构师"}