"首次提交"

This commit is contained in:
Ekko.bao 2024-06-08 15:01:12 +08:00
parent 6e0f708d0a
commit 84349a2469
112 changed files with 3272 additions and 0 deletions

4
.gitignore vendored Normal file → Executable file
View File

@ -13,4 +13,8 @@ Cargo.lock
# MSVC Windows builds of rustc generate these, which store debugging information # MSVC Windows builds of rustc generate these, which store debugging information
*.pdb *.pdb
*.exe
*/.git
*/.vscode

0
README.md Normal file → Executable file
View File

1
enum_learn/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

8
enum_learn/Cargo.toml Executable file
View File

@ -0,0 +1,8 @@
[package]
name = "enum_learn"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

118
enum_learn/src/main.rs Executable file
View File

@ -0,0 +1,118 @@
use std::{net::IpAddr, string};
fn main() {
println!("Hello, world!");
enum_learn();
enum_option();
}
fn enum_learn(){
//定义枚举使用关键字enum不附带数据
enum IpAddr_test{
V4,
V6,
}
struct ipv4{
addr0:u8,
addr1:u8,
addr2:u8,
addr3:u8,
}
//定义枚举并附加一些数据
enum IpAddr{
//元组
V4(u8,u8,u8,u8),
V6(String),
//匿名结构体
V4_1{addr0:u8, addr1:u8, addr2:u8, addr3:u8},
//具名结构体, 使用元组和匿名结构体的方式组织
V4_2(ipv4),
V4_3{addr:ipv4},
}
//可通过impl 定义枚举的方法&关联函数。和struct类型的impl的使用类似
impl IpAddr{
fn print_addr(&self){
//使用match方法匹配枚举值并提取出其相关的数据使用
match self {
//使用元组的方式那么这里对应的数据也是需要用 () 进行解构的
IpAddr::V4(val0,val1,val2,val3) => {
println!("addr is {}.{}.{}.{}", val0, val1,val2,val3);
},
IpAddr::V6(addr_str) => {
println!("addr is {}", addr_str);
},
//使用结构体的方式那么这里对应的数据也是需要用 {} 进行解构的
IpAddr::V4_1 { addr0, addr1, addr2, addr3 } => {
println!("addr is {}.{}.{}.{}", addr0, addr1,addr2,addr3);
},
IpAddr::V4_2(addr) => {
println!("addr is {}.{}.{}.{}", addr.addr0, addr.addr1, addr.addr2, addr.addr3);
},
IpAddr::V4_3{addr} => {
println!("addr is {}.{}.{}.{}", addr.addr0, addr.addr1, addr.addr2, addr.addr3);
},
//匹配其他情况
_ => {
println!("not support");
}
}
}
}
//函数体内可以再定义函数。其作用域只在本函数内
fn sub(){
//使用元组的方式初始化
let home = IpAddr::V4(127,0,0,1);
let lookup = IpAddr::V6(String::from("::"));
//使用结构体的方式初始化
let home1 = IpAddr::V4_1{addr0:127,addr1:0,addr2:0,addr3:1};
let addr = ipv4{addr0:127,addr1:0,addr2:0,addr3:1};
//具名结构体,使用元组
let home2 = IpAddr::V4_2(addr);
//具名结构体,使用结构体的方式初始化
let home3 = IpAddr::V4_3{addr:ipv4{addr0:127,addr1:0,addr2:0,addr3:1}};
home.print_addr();
lookup.print_addr();
home1.print_addr();
home2.print_addr();
home3.print_addr();
}
//调用函数, 如果局部的函数和全局的有同名的。优先局部的
sub();
}
/* 在rust中没有NULL的使用其使用一个特殊的枚举Option<T> 来表达可能有值或者没有值的意思
使Option的变量必须对其进行转化T方可使用使
*/
fn enum_option(){
let mut num1 = Some(2); // 编译器可自动推导出类型 T
let num2 = 10;
let num3: Option<i64> = Some(5);// 也可以显式进行指定
let num4: Option<i32> = None; // 如果未None时编译器无法自动推断类型所以需要显式进行指定 T 是什么类型
let str1 = Some(String::from("a Option string"));
// case1: 不能直接使用 + 来操作一个Option<T>和T因为是两个不同的类型不能直接相加
//let ret1:i32 = num1 + num2;
fn add(num1:Option<i32>, num2:i32) -> i32{
match num1 {
Some(num) => num + num2,// 使用match仅仅在其有值的情况下进行使用
None => {
println!("num1 is None!");
num2
},
}
}
let ret1 = add(num1, num2);
println!("{:?}(num1) + {}(num2) => ret1: {}", num1, num2, ret1);
// case2: Option<T> 没有 + 操作符,也不能直接相加
//let ret2:i32 = num1 + num3;
num1 = num4; // 可以将 Option<T> (T相同) 的变量之间进行所有权的转移
//num1 = num3; // num3 是 Option<i64>, num1是 Option<i32> 不能绑定
println!("{:?}(num1) + {}(num2) => ret2: {}", num1, num2, ret2);
}

1
function/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

8
function/Cargo.toml Executable file
View File

@ -0,0 +1,8 @@
[package]
name = "function"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

65
function/src/main.rs Executable file
View File

@ -0,0 +1,65 @@
fn main() {
println!("Hello, world!");
another_function();
display(4);
display(5);
let ret = inc(5);
println!("5 + 1 = {}", ret);
let ret = inc1(5);
println!("5 + 1 = {}", ret);
let ret = inc2(5);
println!("5 + 1 = {}", ret);
ThisIsAfunction();
}
//定义一个函数。使用关键字fn
//函数的定义可以在调用后,无需先申明后使用
fn another_function (){
println!("another_function");
}
//函数的param必须标注类型但是不能类型前置
//fn display(i32 x){
fn display(x:i32){
println!("x is {}", x);
}
/*
C语言一致使 /* */
使使 -> pythno的类型标注类似python是可选的
*/
fn inc(x:i32) -> i32{
let ret = x + 1;
return ret
}
fn inc1(x:i32) -> i32{
//函数的返回值默认为最后一个表达式的值作为返回值,
//所以这里不能加上分号,加上分号就变成了语句了
x + 1
}
//rust的函数明明必须使用snake_style 下面这种风格会有警告
fn ThisIsAfunction(){
}
fn inc2(x:i32) -> i32{
/*
C语言的宏块({...}) C里面最后的返回值的代码也要加分号
*/
//所以这里使用y作为代码块的返回值并且后面不能加分号
let ret = {
let y = x + 1;
y
}; //这里必须要加分号,因为 let ret ={...}; 加了分号才属于一整个完整的语句,不然语法错误了,{...} 这部分属于表达式
/*
*/
//{ret} //方式1: ret作为代码块的值代码块的值又作为函数的返回值但是没必要
//ret //方式2单独表达式作为函数返回值
return ret; //方式3当函数提前返回时必须使用return 关键字当然其放到最后显式的调用也是ok的
}

1
generics/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

9
generics/Cargo.toml Executable file
View File

@ -0,0 +1,9 @@
workspace = { members = ["trait_learn"] }
[package]
name = "generics"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

68
generics/src/main.rs Executable file
View File

@ -0,0 +1,68 @@
fn main() {
println!("Hello, world!");
generics();
generics1();
}
fn generics() {
// 定义一个支持多种类型的结构体,元素的类型取决于实际代码
struct Point <T, U> {
x:T,
y:U,
}
let p1 = Point {
x : 10, //i32
y : 'c', //char
};
let p1 = Point {
x : 10, //i32
y : 10.3, // f64
};
let p1 = Point {
x : '1', // char
y : 10.3, // f64
};
}
fn generics1() {
#[derive(Debug)]
struct Point <T, U> {
x:T,
y:U,
}
//对于point的实现也使用泛型
/* 这里impl后加 <T, U> 是因为后续的Point里面指定的类型T,U就是由此来的
V和W是因为V和W是函数mixup中才使用的并不是和Point有关的泛型T和U,
使
*/
impl<T, U> Point<T, U> {
//impl<U, T> Point<T, U> { // 这是正确的
//impl<T, U, V, W> Point<T, U> { //这是错误的
fn new(x:T, y:U) -> Point<T, U>{
Point{
x,
y,
}
}
//这里使用了泛型V和W是为了有别于上面的T和U因为self的类型已经是T和U了
//如果这里还是T和U那么其实就是限制了other的类型必须是和self一样的类型
//这里使用V和W就是表示可以是任意的类型。
//返回值是T和W就是说明他用的是self的x和other的Y
//fn mixup <I, V, W>(self, other: Point<V,W>, z:I) -> Point<T,W>{ // 有其他参数就继续加泛型名即可
fn mixup <V, W>(self, other: Point<V,W>) -> Point<T,W>{
Point{
x:self.x,
y:other.y,
}
}
}
let point = Point::new(32, 'a');
let point1 = Point::new(23.0, 100);
let point2 = point1.mixup(point);
println!("{:?}", point2);
}

1
guessing_game/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

9
guessing_game/Cargo.toml Executable file
View File

@ -0,0 +1,9 @@
[package]
name = "guessing_game"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rand='0.8.5'

29
guessing_game/src/main.rs Executable file
View File

@ -0,0 +1,29 @@
//prelude 预导入: Rust 会导入一些默认的模块供给使用但是其他的就需要手动使用use导入
use std::{cmp::Ordering, io};
use rand::{Rng, thread_rng};
fn main() {
println!("猜数游戏");
let mut rng = thread_rng();
let secret_num:u32= rng.gen_range(1..100);
// println!("神秘数字是 {}", secret_num);
loop {
println!("请猜测一个数字");
let mut guess = String::new();
let str_len = io::stdin().read_line(&mut guess).expect("读取行错误错误");
// println!("你输入的内容长度是 {} 内容为:{}",str_len, guess);
let guess:u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => {
println!("字符串非数字无法解析");
continue;
}
};
match guess.cmp(&secret_num){
Ordering::Less => println!("你猜的数字太小"),
Ordering::Greater => println!("你猜的数字太大"),
Ordering::Equal => {println!("你猜对了");break;},
}
}
}

1
hash_map/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

8
hash_map/Cargo.toml Executable file
View File

@ -0,0 +1,8 @@
[package]
name = "hash_map"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

46
hash_map/src/main.rs Executable file
View File

@ -0,0 +1,46 @@
use std::collections::HashMap;
fn main() {
println!("Hello, world!");
hash_map_learn();
}
fn hash_map_learn() {
/* 创建一个hashmap使用显式指定key和value的类型的方式
使insert方法进行元素的插入时即可自动推导出类型
key的类型必须一致value的类型也必须一致
*/
let mut map1:HashMap<String, i32> = HashMap::new();
//插入一个元素
map1.insert(String::from("aa"), 1);
//插入同名元素,会覆盖原有的元素
map1.insert(String::from("aa"), 2);
println!("{:?}", map1);
//尝试访问并在没有对应数据的情况下插入新的值,这样可以做到不覆盖已有元素
map1.entry(String::from("aa")).or_insert(3);// 如果元素aa不存在则插入aa:3
map1.entry(String::from("bb")).or_insert(4);// 如果元素aa不存在则插入bb:4
println!("{:?}", map1);
let e = map1.entry(String::from("cc"));
println!("{:?}", e);
let e = map1.entry(String::from("aa"));
println!("{:?}", e);
//利用hashmap统计单词的个数。
let str1 = String::from("hello world wonderful world 你好 世界 美丽 世界");
let mut map1 = HashMap::new();
//将单词使用空格切割开 并遍历
for word in str1.split_whitespace() {
//这里or_insert的返回值是hashmap对应word的键值对的值的可变引用
//这里就是如果没找到word那么就插入一个word和cnt的键值对。值就是0。并将值的可变引用返回
//这里如果找到对应的word那么就不会覆盖原来的值仅仅是将值的可变引用返回
//所以无论如何我们都能获得一个该word对应出现次数的可变引用
let count = map1.entry(word).or_insert(0);
//将值所对应的可变引用进行+1表示数字个数多了一个
*count = *count + 1;
}
println!("{:?}", map1);
}

1
hello_cargo/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

8
hello_cargo/Cargo.toml Executable file
View File

@ -0,0 +1,8 @@
[package]
name = "hello_cargo"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

3
hello_cargo/src/main.rs Executable file
View File

@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}

1
if_else/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

8
if_else/Cargo.toml Executable file
View File

@ -0,0 +1,8 @@
[package]
name = "if_else"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

68
if_else/src/main.rs Executable file
View File

@ -0,0 +1,68 @@
fn main() {
println!("Hello, world!");
test_function()
}
fn test_function(){
let num = 34;
//if num {//判断条件必须是bool类型的此处num类型是i32无法进行判断
if num != 0 { // 使用这样的方法来产生一个bool类型的结果提供给if进行判断
/* 当有多个条件时为了防止混乱可以在多个条件上加括号,条件组合的最终结果没必要加 和python类似 */
//if (num != 0) && (num > 0) { //✅
//if ((num != 0) && (num > 0)) { //❎
println!("condition is true");
}else{
println!("condition is false");
}
/* 使用if来构建三元表达式
C中三元运算符我们使用 cond ? true : false;
rust中if是表达式而不是语句使
*/
let cond = false;
let ret = if cond {true} else {false}; //使用if构建的三元表达式
/* if 表达式可以多级使用 用法和C类似
rust中使用超过一个if else就应该考虑使用match c中的switch类似
*/
let num = 2;
if (num >= 4) && (num % 4 == 0) {
println!("{} can div by 4", num);
} else if num >= 3 && (num % 3 == 0) {
println!("{} can div by 3", num);
}
else if (num > 2 || num == 2) && num % 2 == 0 {
println!("{} can div by 2", num);
}else{
println!("{} cant div by 4 or 3 or 2", num);
}
/* 在rust中if else的值必须保持一致 */
//case1if 和else的代码块值类型不一致。if的是i32 else的是f64是不可以的
// 因为rust是静态强类型。在编译阶段必须直到ret的类型但是如果if else类型不一致会导致无法推断
//let ret = if 2 == 2 {2} else {2.0};
//case2: 如果没有左值也就是没有接收if表达式的变量那么代码块里面就不能有值产生或者说值只能是()
if 2 == 2 { //没有人要if表达式的结果
//2 //❎ 不能产生值
//() //✅ //代码块值只能是 ()
}else{
//2.0 //❎
// //✅ //nothing编译器自动认为是 ()
}
//如果显式的规定的左值的结果那么if表达式里面的代码块值只能是左值类型
//let ret: bool = if 2 == 2 {"true"} else{"false"}; //变量是bool但是表达式里面是字符串 ❎
//如果没有显式指定,编译器会自动推导
let ret = if 2 == 2 {"true"} else{"false"}; //变量没有类型,编译自动推到出来 ✅
// test () value
let ret = if 2 == 2 {} else{};
if ret == () { //判断是是否为()
println!("ret if ()")
}else{
println!("ret is not ()")
}
}

1
iterator_learn/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

8
iterator_learn/Cargo.toml Executable file
View File

@ -0,0 +1,8 @@
[package]
name = "iterator_learn"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

176
iterator_learn/src/main.rs Executable file
View File

@ -0,0 +1,176 @@
use std::{env::VarsOs, path::Iter};
fn main() {
iterator_learn();
}
fn iterator_learn() {
let v1 = vec![1, 2, 3];
let iter = v1.iter();
//使用循环遍历迭代器
for it in iter {
println!("{}", it);
}
//使用next方法遍历迭代器
let mut iter = v1.iter();
loop {
let item = match iter.next() {
Some(it) => it,
None => break,
};
println!("{}", item)
}
let ret = v1.iter().skip(1);
for it in ret {
println!("{}", it);
}
}
#[test]
fn iterator_demonstration() {
let v1 = vec![1, 2, 3];
// next 方法 会获得所有权。必须将其变为mut
let mut iter = v1.iter();
assert_eq!(iter.next(), Some(1).as_ref());
assert_eq!(iter.next(), Some(2).as_ref());
assert_eq!(iter.next(), Some(3).as_ref());
assert_eq!(iter.next(), None);
}
#[test]
fn iterator_create1() {
let v1 = vec![1, 2, 3];
let mut iter = v1.iter().map(|x| x + 1);
assert_eq!(iter.next(), Some(2));
assert_eq!(iter.next(), Some(3));
assert_eq!(iter.next(), Some(4));
assert_eq!(iter.next(), None);
// collect 方法返回值需要手动指定。以便于rust编译推断其所需构造的类型
let ret: Vec<i32> = v1.iter().map(|x| x + 1).collect();
assert_eq!(vec![2, 3, 4], ret);
}
#[test]
fn closure_test() {
let mut offset = 10;
//闭包可以手动指定类型也可以自动推断,但是一旦确定一种调用方法后将不能再改变参数类型
let func = |x: i32, y, z| -> i32 { x + y + z + offset };
fn sub_fun<F>(func: F, x: i32, y: i32, z: i32) -> i32
where
F: Fn(i32, i32, i32) -> i32,
{
func(x, y, z)
}
//offset = 20; // 不可以修改offset的值因为其已经被闭包作为一个一个不可变引用使用了
assert_eq!(sub_fun(func, 1, 2, 3), 6 + offset);
//闭包的生命周期已经结束所以offset可以被修改了
offset = 20;
assert_eq!(offset, 20);
}
#[test]
fn filter_by_size() {
#[derive(PartialEq, Debug)]
struct Shoe {
size: u32,
style: String,
}
fn shoes_in_my_size(shoes: Vec<Shoe>, size: u32) -> Vec<Shoe> {
//into_iter 方法会获得shoes的所有权所以不能再使用shoes
shoes.into_iter().filter(|x| size == x.size).collect()
}
let shoes = vec![
Shoe {
size: 10,
style: String::from("sneaker"),
},
Shoe {
size: 13,
style: String::from("sandal"),
},
Shoe {
size: 10,
style: String::from("boot"),
},
];
let ret = shoes_in_my_size(shoes, 10);
//不可以再使用shoes所有权已经到了 shoes_in_my_size 里面
// shoes.push(Shoe {
// size: 10,
// style: String::from("sneaker"),
// });
assert_eq!(
vec![
Shoe {
size: 10,
style: String::from("sneaker"),
},
Shoe {
size: 10,
style: String::from("boot"),
},
],
ret
);
}
struct Counter {
cnt: u32,
}
impl Counter {
fn new() -> Counter {
Counter { cnt: 0 }
}
}
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
if self.cnt < 5 {
self.cnt += 1;
Some(self.cnt)
} else {
None
}
}
}
#[test]
fn custom_iterator() {
let mut count = Counter::new();
assert_eq!(count.next(), Some(1));
assert_eq!(count.next(), Some(2));
assert_eq!(count.next(), Some(3));
assert_eq!(count.next(), Some(4));
assert_eq!(count.next(), Some(5));
assert_eq!(count.next(), None);
}
#[test]
fn custom_iterator1() {
let count: Vec<(u32, u32)> = Counter::new()
.zip(Counter::new().filter(|x| x % 2 == 0))
.collect();
assert_eq!(count, vec![(1, 2), (2, 4)]);
let count: Vec<u32> = Counter::new()
.zip(Counter::new().filter(|x| x % 2 == 0))
.map(|(a, b)| a + b)
.collect();
assert_eq!(count, vec![3, 6]);
let count: u32 = Counter::new()
.zip(Counter::new().filter(|x| x % 2 == 0))
.map(|(a, b)| a + b)
.sum();
assert_eq!(count, 9 );
}

1
learn_test_8/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

8
learn_test_8/Cargo.toml Executable file
View File

@ -0,0 +1,8 @@
[package]
name = "learn_test_8"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

126
learn_test_8/src/main.rs Executable file
View File

@ -0,0 +1,126 @@
use std::{collections::HashMap, fmt::Debug};
fn main() {
println!("Hello, world!");
sta_array();
pig_latin();
company_empolyer_mgn()
}
fn sta_array () {
let numbers = vec![-6,2,2,4,5,6,6,100,8,20,10];
let mut avg = 0;
//统计平均値
for num in &numbers {
avg = (avg + num) / 2;
}
println!("the average of {:?} is {}", numbers, avg);
//统计出现次数最多的数字
let mut map = HashMap::new();
#[derive(Debug)]
struct MaxNumInfo{
num:i32,
cnt:i32,
}
let mut max_num = MaxNumInfo {
num:0,
cnt:0,
};
impl MaxNumInfo{
fn from(other:&MaxNumInfo) -> MaxNumInfo{
MaxNumInfo{
num: other.num,
cnt: other.cnt,
}
}
}
let mut max_numv: Vec<MaxNumInfo> = Vec::new();
for num in &numbers {
let cnt = map.entry(num).or_insert(0);
*cnt += 1;
if *cnt >= max_num.cnt {
if *cnt > max_num.cnt {
max_numv.clear();
}
max_num.cnt = *cnt;
max_num.num = *num;
max_numv.push(MaxNumInfo::from(&max_num));
}
}
println!("the max count in {:?} is {:?}", numbers, max_numv);
//统计中位数
let mut order = numbers.clone();
order.sort();
let size = order.len() / 2;
let num = order[size];
println!("median of {:?} is {:?}", numbers, num);
}
fn pig_latin () {
let vowel = vec!['a','e','i','o','u'];
let words = vec!["apple", "first"];
let mut new_words = Vec::new();
for word in &words {
for v in &vowel {
if let Some(first_char) = word.chars().next() {
if first_char == *v {
new_words.push(String::from(*word) + "-hay");
} else {
new_words.push(String::from(&(*word)[1..]) + "-" + &first_char.to_string() + "ay");
}
break;
}
}
}
println!("after process {:?} to {:?}", words, new_words);
}
fn company_empolyer_mgn() {
struct empolyer_mgn{
map:HashMap<String,Vec<String>>,
}
impl empolyer_mgn {
fn new() -> empolyer_mgn {
empolyer_mgn {
map:HashMap::new(),
}
}
fn add(&mut self, depart:String, name:String) {
let employers = self.map.entry(depart).or_insert( Vec::new());
employers.push(name);
}
fn get_all_emplyer(&mut self) {
print!("total empolyer is ");
for (key, value) in self.map.iter() {
print!("{:?} ", value);
}
println!("");
}
fn get_emplyer(&mut self, depart:String) {
match self.map.entry(depart) {
std::collections::hash_map::Entry::Occupied(entry) => {
println!("in {} empolyer is {:?}", entry.key(), entry.get());
},
std::collections::hash_map::Entry::Vacant(entry) => {
println!("in {} has no emplyer found", entry.key())
},
}
}
}
let mut mgn = empolyer_mgn::new();
mgn.add(String::from("项目部门"), String::from("Sally"));
mgn.add(String::from("销售部门"), String::from("Amir"));
mgn.get_all_emplyer();
mgn.get_emplyer(String::from("研发部门"));
mgn.get_emplyer(String::from("销售部门"));
mgn.get_emplyer(String::from("项目部门"));
}

1
life_cycle/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

8
life_cycle/Cargo.toml Executable file
View File

@ -0,0 +1,8 @@
[package]
name = "life_cycle"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

83
life_cycle/src/main.rs Executable file
View File

@ -0,0 +1,83 @@
fn main() {
println!("Hello, world!");
life_cycle();
}
fn life_cycle() {
{
// 这样定义会使得编译器无法识别返回的数据是x还是无法知道返回的这个借用的生命周期是多少也就无法防止悬垂引用
//fn longest(x:&str, y:&str) -> &str {
/* 生命周期是泛型参数的一种,可以像使用泛型参数那样使用生命周期,他的语法是单引号+一个小写字母,生命周期标注加在&之后。
x和y的生命周期都是'a, x和y的生命周期并不是一样的'a x和y中较小的一个
x还是y都能够保证有效
*/
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
{
//test 1
let str1 = "str1 ....";
let str2 = "str2";
let lstr = longest(str1, str2);
println!("longest str is {}", lstr);
}
//test 2
let str1 = "str1 ....";
let lstr;
{
let t = String::from("str2");
/* 如果是一个字符串字面值那么就没有问题。因为他是static的生命周期 */
let str2: &str = "str2";
/* 如果是一个字符串引用那就不行。因为字符串t会在大括号之后生命结束了其引用也将失效
longest的结果打印,
使str1才是真正的返回的引用
使str1和str2的字符串长度
*/
//let str2: &str = t.as_str();
lstr = longest(str1, str2);
}
println!("longest str is {}", lstr);
}
{
// 这里固定返回x将生命周期的标注放在x和返回值上
// 这里必须标注生命周期因为虽然我们知道返回值是x但是编译器并不会分析代码的执行
// 所以这里必须显式的标注x和返回值的生命周期
fn longest<'a>(x: &'a str, y: &str) -> &'a str {
x
}
let str1 = "str1 ....";
let lstr;
{
let t = String::from("str2");
/* 因为longest的返回值的生命周期固定和x相同
使y是一个临时的字符串的引用也不会有问题
*/
let str2: &str = t.as_str();
lstr = longest(str1, str2);
// 但是如果将str2传入x那么就会报错因为str2的生命周期不足以在大括号外使用
//lstr = longest(str2, str1);
}
println!("longest str is {}", lstr);
}
{
#[derive(Debug)]
struct test<'a, T> {
str1: &'a T,
}
let var;
{
let t = String::from("str1");
var = test { str1: t.as_str() }; // 使用t的字符串引用
println!("test: {:?}", var);
}
//println!("test: {:?}", var); // 在t的生命周期结束后在使用就导致报错
}
}

1
loop_while_for/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

8
loop_while_for/Cargo.toml Executable file
View File

@ -0,0 +1,8 @@
[package]
name = "loop_while_for"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

114
loop_while_for/src/main.rs Executable file
View File

@ -0,0 +1,114 @@
fn main() {
println!("Hello, world!");
loop_fun();
while_fun();
for_fun();
}
/* rust 提供了三种循环方式
loopwhilefor
*/
fn loop_fun(){
//loop 循环,一直循环直到主动退出
//loop 从功能上和while true 是一样的,
//但是为什么说要单独列出来我目前还不是很清楚
let mut num = 100;
loop {
// num --;// 不允许这样写
num -= 1;
if num > 10{
//提前结束本次循环
continue;
}
if num < 0 {
// 主动结束循环
break;
}
println!("{}", num)
} // 这里是不需要加上分号的,因为他不是一个语句
println!("go,go,go");
// loop也是表达式所以其可以产生值作为右值
let mut num = 100;
let cond = 3%num;
let ret = loop {
num -=1;
if cond == num{
//break;//这样主动退出之后ret的值将会是一个
//break //这样也是可以的和上面效果一致
break num; //case1 这样会把num作为整个loop表达式的值给到ret ret类型就是i32
//break num //case2 不加上分号也是可以的
/* case3 可以换行写,但是要加分号了,不然跨了行不会被认为是一个完整的语句,
😅
break
num;
*/
break 123;//break语句后的代码不会被执行到。
}
};
println!("ret is {}", ret)
}
fn while_fun(){
// while 循环,
// 检查条件如果符合就进入循环并直到主动退出或者条件不满足
// 每轮循环都会检查条件
let mut num = 30;
// 循环条件的检查,满足才会开始&继续循环
while num > 0 {
if num > 10{
println!("{} is > 10, I cant process -_-!", num);
break; //提前终止循环
}
if num % 2 == 0 {
println!("{}!", num);
num -= 1;
continue;// 提前终止本轮循环
}
println!("{}", num);
num -= 1;//修改循环条件
} // 这里同样不用加分号因为while 是表达式不是语句
if num == 0{
println!("go,go,go");
}
let mut num = 30;
// while 表达式可作为右值但是在里面不能用break返回其值
// 因为while有可能是条件不满足而结束此时是没有值的如果break指定了返回值这样就会导致
// 编译器无法在编译期间确定ret的类型
// 这也引发了我对loop的思考是否就是while这种特性导致需要一种完全交给开发者可控的退出方式的循环才催生了loop👻
// 因为loop 的退出是完全开发者编写的退出时机,也就使得可以带有返回值
let ret = while num > 0 {
num = 0;
//break num;//不可以像loop那样带有值
break;
}; // 这里必须加分号因为while 表达式作为右值和let ret一起构成完整语句
}
fn for_fun(){
//for 循环 语法就是 for xxx in yyy {}
// yyy是一个可迭代的对象比如数组range等
// for 循环相比较while,loop可以安全的遍历迭代对象而不用担心越界的问题。
let ary = [0, 1, 2, 3, 4, 5];
//遍历整个数组并打印
for item in ary.iter() {
println!("{}", item);
}
//从100到-1遍历一遍 range: start..end
let rng = 100..1;
for item in 100..-1 {
if item > 10 {
continue;
}
if item <=0 {
break;// 和while 一样可以提前退出但是无法携带值
}
println!("{}", item);
}
}

3
main.rs Executable file
View File

@ -0,0 +1,3 @@
fn main() {
println!("hello world ekko.bao")
}

1
minigrep/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

8
minigrep/Cargo.toml Executable file
View File

@ -0,0 +1,8 @@
[package]
name = "minigrep"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

106
minigrep/src/lib.rs Executable file
View File

@ -0,0 +1,106 @@
use std::error::Error;
use std::fmt;
pub struct Config {
pub query: String,
pub filename: String,
pub sensitive: bool,
}
impl Config {
pub fn new(args: &[String]) -> Result<Config, &'static str> {
if args.len() < 2 {
return Err("args len less then 2");
}
let query = args[0].clone();
let filename = args[1].clone();
let sensitive = std::env::var("CASE_SENSITIVE").is_ok();
Ok(Config {
query,
filename,
sensitive,
})
}
}
pub struct GrepRet {
line: i32,
context: String,
}
impl GrepRet {
fn new(line: i32, context: &str) -> GrepRet {
GrepRet {
line,
context: context.to_string(),
}
}
}
impl fmt::Display for GrepRet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "line:{}: {}", self.line, self.context)
}
}
pub fn run(config: &Config) -> Result<Vec<GrepRet>, Box<dyn Error>> {
let context = std::fs::read_to_string(&config.filename)?;
if config.sensitive {
Ok(search_sensitive(&config.query, &context))
} else {
Ok(search_insensitive(&config.query, &context))
}
}
fn search_sensitive(query: &str, context: &String) -> Vec<GrepRet> {
let mut idx = 0;
let mut result = Vec::new();
for line in context.lines() {
idx += 1;
if line.contains(query) {
result.push(GrepRet::new(idx, line));
}
}
result
}
fn search_insensitive(query: &str, context: &String) -> Vec<GrepRet> {
let mut idx = 0;
let mut result = Vec::new();
for line in context.lines() {
idx += 1;
let lower = line.to_lowercase();
if lower.contains(&query.to_lowercase()) {
result.push(GrepRet::new(idx, line));
}
}
result
}
#[cfg(test)]
pub mod test {
use super::*;
#[test]
fn grep_new1() {
let line = 10;
let context = "zzz";
let grep_ret = GrepRet::new(line, context);
assert_eq!(line, grep_ret.line);
assert_eq!(context, grep_ret.context);
}
#[test]
fn grep_new2() {
let line = 10;
let context = "zzz";
let grep_ret = GrepRet::new(line, context);
assert_ne!(!line, grep_ret.line);
assert_eq!(context, grep_ret.context);
}
#[test]
#[ignore] // cargo test -- --ignored
fn grep_new3() {
let line = 10;
let context = "zzz";
let grep_ret = GrepRet::new(line, context);
assert_ne!(!line, grep_ret.line);
assert_eq!(context, grep_ret.context);
}
}

25
minigrep/src/main.rs Executable file
View File

@ -0,0 +1,25 @@
use std::env;
use std::process;
use minigrep;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() < 3 {
eprintln!("Usage: {} <text> <input file>", &args[0]);
return;
}
let args = &args[1..];
let config = minigrep::Config::new(args).unwrap_or_else(|err| {
println!("Problem: {}", err);
process::exit(-1);
});
let result = minigrep::run(&config).unwrap_or_else(|err| {
println!("Problem: {}", err);
process::exit(-1);
});
println!("find {} in {}, is:", config.query, config.filename);
for it in result {
println!("{}", it);
}
}

9
minigrep/test.txt Executable file
View File

@ -0,0 +1,9 @@
ekko.bao
emma.wang
wwww
to
rust
rust
today is a nice day
to you beast
EKKO

9
minigrep/tests/intergation.rs Executable file
View File

@ -0,0 +1,9 @@
use minigrep;
#[test]
#[should_panic]
fn grep_new2() {
let args = vec![String::from("zzz"), String::from("zzz.txt")];
let config = minigrep::Config::new(&args).unwrap();
let _ = minigrep::run(&config).unwrap();
}

1
minigrep_iterator/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

8
minigrep_iterator/Cargo.toml Executable file
View File

@ -0,0 +1,8 @@
[package]
name = "minigrep"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

132
minigrep_iterator/src/lib.rs Executable file
View File

@ -0,0 +1,132 @@
//! mini grep
//! 实现一个简易版本的grep工具的功能通过传入要查询的字符串和文件名会遍历每一行文件内容并将其输出到终端
//!
//! ***注意***
//! 可通过 CASE_SENSITIVE 环境变量来进行设定是否忽略大小写进行匹配。
use std::error::Error;
use std::fmt;
pub struct Config {
/// 需要查询的字符串
pub query: String,
/// 检索字符串的文件名
pub filename: String,
/// 是否大小写敏感
/// - true: 大小写敏感
/// - false 忽略大小写
pub sensitive: bool,
}
impl Config {
/// Config 的构造函数传入一个string的iter会将其构造为一个Config并返回如果失败则返回一个Err并带有说明的字符串
///
/// # Example
/// ```
/// use minigrep::Config;
/// let mut args = vec![String::from("to"), String::from("test.txt")];
/// let cfg = Config::new(args.into_iter()).unwrap();
/// assert_eq!(cfg.query, "to");
/// assert_eq!(cfg.filename, "test.txt");
/// ```
pub fn new<T>(mut args: T) -> Result<Config, &'static str>
where
T: Iterator<Item = String>,
{
let query = args.next().unwrap();
let filename = args.next().unwrap();
let sensitive = std::env::var("CASE_SENSITIVE").is_ok();
Ok(Config {
query,
filename,
sensitive,
})
}
}
pub struct GrepRet {
line: i32,
context: String,
}
impl GrepRet {
fn new(line: i32, context: &str) -> GrepRet {
GrepRet {
line,
context: context.to_string(),
}
}
}
impl fmt::Display for GrepRet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "line:{}: {}", self.line, self.context)
}
}
/// 字符串匹配的实操入口函数,
/// - 入参:<br>
/// Config
/// - 返回值:<br>
/// 查询到的匹配字串的文本行以及行号如果发生错误则返回Err
pub fn run(config: &Config) -> Result<Vec<GrepRet>, Box<dyn Error>> {
let context = std::fs::read_to_string(&config.filename)?;
if config.sensitive {
Ok(search_sensitive(&config.query, &context))
} else {
Ok(search_insensitive(&config.query, &context))
}
}
fn search_sensitive(query: &str, context: &String) -> Vec<GrepRet> {
let mut idx = 0;
let mut result = Vec::new();
for line in context.lines() {
idx += 1;
if line.contains(query) {
result.push(GrepRet::new(idx, line));
}
}
result
}
fn search_insensitive(query: &str, context: &String) -> Vec<GrepRet> {
let mut idx = 0;
let mut result = Vec::new();
for line in context.lines() {
idx += 1;
let lower = line.to_lowercase();
if lower.contains(&query.to_lowercase()) {
result.push(GrepRet::new(idx, line));
}
}
result
}
#[cfg(test)]
pub mod test {
use super::*;
#[test]
fn grep_new1() {
let line = 10;
let context = "zzz";
let grep_ret = GrepRet::new(line, context);
assert_eq!(line, grep_ret.line);
assert_eq!(context, grep_ret.context);
}
#[test]
fn grep_new2() {
let line = 10;
let context = "zzz";
let grep_ret = GrepRet::new(line, context);
assert_ne!(!line, grep_ret.line);
assert_eq!(context, grep_ret.context);
}
#[test]
#[ignore] // cargo test -- --ignored
fn grep_new3() {
let line = 10;
let context = "zzz";
let grep_ret = GrepRet::new(line, context);
assert_ne!(!line, grep_ret.line);
assert_eq!(context, grep_ret.context);
}
}

25
minigrep_iterator/src/main.rs Executable file
View File

@ -0,0 +1,25 @@
use std::env;
use std::process;
use minigrep;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() < 3 {
eprintln!("Usage: {} <text> <input file>", &args[0]);
return;
}
let args1 = args.into_iter().skip(1);
let config = minigrep::Config::new(args1).unwrap_or_else(|err| {
println!("Problem: {}", err);
process::exit(-1);
});
let result = minigrep::run(&config).unwrap_or_else(|err| {
println!("Problem: {}", err);
process::exit(-1);
});
println!("find {} in {}, is:", config.query, config.filename);
for it in result {
println!("{}", it);
}
}

9
minigrep_iterator/test.txt Executable file
View File

@ -0,0 +1,9 @@
ekko.bao
emma.wang
wwww
to
rust
rust
today is a nice day
to you beast
EKKO

1
module_learn/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

8
module_learn/Cargo.toml Executable file
View File

@ -0,0 +1,8 @@
[package]
name = "module_learn"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

7
module_learn/src/bin/app1.rs Executable file
View File

@ -0,0 +1,7 @@
/*
rust cratesrc/bin rs就是一个二进制包文件
crate app1使cargo build --bin app1
*/
fn main() {
println!("Hello, world! app1");
}

3
module_learn/src/bin/app2.rs Executable file
View File

@ -0,0 +1,3 @@
fn main() {
println!("Hello, world! app2");
}

132
module_learn/src/lib.rs Executable file
View File

@ -0,0 +1,132 @@
/*
rust library的单元包src/lib.rscargo new的时候创建的工程名
使 cargo build --lib
*/
//该模块位public的可以被外部的code进行导入使用
pub mod level0_mod1{
//定义一个public的函数可以暴露给外部调用
pub fn func(){
println!("This is level0_mod1::func");
//fun1属于本模块内的私有函数。模块内的code 是可以使用的,
fun1();
levl1_mod1::func();
//levl1_mod1::fun1是私有的只能在levl1_mod1 子模块内使用。
//levl1_mod1::fun1();
//levl2_mod1 是私有的只能在 levl1_mod2 模块内使用。不能被更外部的code使用
//levl1_mod2::levl2_mod1::func();
}
//定义一个私有的函数。外部不能直接使用只能模块内部的code可以使用
fn fun1() {
println!("This is level0_mod1::func1");
levl1_mod1::func();
}
//定义一个私有的模块。只能被同级的其他模块及其子模块调用不能被外部的code调用
mod levl1_mod1 {
pub fn func(){
println!("This is levl1_mod1::func");
self::fun1();
}
//这一一个私有模块中的私有函数。只能被同模块下的其他code调用不能被本模块外的code调用
fn fun1() {
println!("This is levl1_mod1::func1");
}
}
//定义一个公共的子模块。由于其父模块也是public的所以其可以被外部的code进行调用
pub mod levl1_mod2 {
pub fn func() {
println!("This is levl1_mod2::func");
levl2_mod1::func();
}
mod levl2_mod1 {
pub fn func(){
println!("This is levl2_mod1::func");
//可以使用绝对路径调用函数。根目录就是creat关键字相对于文件系统目录里面/
crate::level0_mod1::levl1_mod1::func();
//也可以使用相对路径进行调用
//self 相当于文件系统里面的 . 代表当前目录,也就是当前模块
//super 相当于文件系统里面的 .. 代表当前目录里的上一级目录,也就是父级模块
self::super::super::levl1_mod1::func();
//这个函数是 levl1_mod1 中私有的不能跨mod使用
//crate::level0_mod1::levl1_mod1::fun1();
//这样也是ok的表示同级模块下的其他函数
self::func1();
}
fn func1(){
println!("This is levl2_mod1::func1");
}
}
}
}
/*
使pub关键字
code进行调用使使
使
使API都定义到一个公共的mod中
pub的API的所述模块
使
*/
//本模块的函数
pub fn func(){
println!("This is level0_mod1::func");
}
//定义一个结构体并加上pub关键字使其暴露给外部使用。
pub struct struct1{
/* 即使结构体是pub的但是不加pub的成员依然是私有的 */
pub member1: i32, //该member是公有的外部可以访问到
member2:i32, //该member是私有的。外部无法访问到
}
impl struct1{
//公共的函数,可以被外部使用
pub fn func(){
println!("This is struct1->func");
}
//私有的函数,不可以被外部使用
fn func1(){
println!("This is struct1->func1");
}
}
//定义一个枚举并加上pub关键字使其暴露给外部使用。
//对于枚举来说 和模块以及struct不同只要枚举是pub的那么其变体也都是pub的
//因为只有只有所有变体都是pub的才能起到最大作用
pub enum enum1{
member1, //该member是公有的外部可以访问到
member2, //该member是公有的外部可以访问到
}
impl enum1 {
//公共的函数,可以被外部使用
pub fn func(){
println!("This is struct1->func");
}
//私有的函数,不可以被外部使用
fn func1(){
println!("This is struct1->func1");
}
}
/* 使用文件目录的形式拆分module以便于减小单个文件的代码量
lib.rs module同名的rs文件module的实现
module还存在子modulemodule同名的文件夹sub_module.rs存放sub_module的实现
src
bin #, rs文件
app1.rs
app2.rs
lib.rs #library lib.rs
tree0_mod1.rs #module tree0_mod1
tree0_mod1 # module tree0_mod1 module的实现源码存放目录
tree1_mod2.rs #module tree1_mod2 tree0_mod1 module
tree1_mod2 # module tree1_mod2 module的实现源码存放目录
tree2_mod1.rs #module tree2_mod1 tree1_mod2 module
*/
pub mod tree0_mod1;

21
module_learn/src/main.rs Executable file
View File

@ -0,0 +1,21 @@
//使用模块路径进行导入, module_learn 代表的是这个lib的名字。 level0_mod1代表是这个lib下的模块
use module_learn::level0_mod1;
//使用{}可以一次性导入多个模块/函数等,不必多行
use module_learn::level0_mod1::{levl1_mod2, func};
use module_learn;
use module_learn::tree0_mod1;
//如果导入时存在重名的可以使用as关键字起一个别名去辨别。
use std::io::Result as ioResult;
use std::fmt::Result as fmtResult;
fn main() {
println!("Hello, world!");
level0_mod1::func();
func();
levl1_mod2::func();
module_learn::func();
tree0_mod1::func();
}

23
module_learn/src/tree0_mod1.rs Executable file
View File

@ -0,0 +1,23 @@
//定义一个public的函数可以暴露给外部调用
pub fn func(){
println!("This is tree0_mod1::func");
//fun1属于本模块内的私有函数。模块内的code 是可以使用的,
fun1();
tree1_mod1::func();
//tree1_mod1::fun1是私有的只能在tree1_mod1 子模块内使用。
//tree1_mod1::fun1();
//tree2_mod1 是私有的只能在 tree1_mod2 模块内使用。不能被更外部的code使用
//tree1_mod2::tree2_mod1::func();
}
//定义一个私有的函数。外部不能直接使用只能模块内部的code可以使用
fn fun1() {
println!("This is tree0_mod1::func1");
tree1_mod1::func();
}
//定义一个私有的模块。只能被同级的其他模块及其子模块调用不能被外部的code调用
mod tree1_mod1;
//定义一个公共的子模块。由于其父模块也是public的所以其可以被外部的code进行调用
pub mod tree1_mod2;

View File

@ -0,0 +1,8 @@
pub fn func(){
println!("This is tree1_mod1::func");
self::fun1();
}
//这一一个私有模块中的私有函数。只能被同模块下的其他code调用不能被本模块外的code调用
fn fun1() {
println!("This is tree1_mod1::func1");
}

View File

@ -0,0 +1,5 @@
pub fn func() {
println!("This is tree1_mod2::func");
tree2_mod1::func();
}
mod tree2_mod1;

View File

@ -0,0 +1,16 @@
pub fn func(){
println!("This is tree2_mod1::func");
//可以使用绝对路径调用函数。根目录就是creat关键字相对于文件系统目录里面/
crate::tree0_mod1::tree1_mod1::func();
//也可以使用相对路径进行调用
//self 相当于文件系统里面的 . 代表当前目录,也就是当前模块
//super 相当于文件系统里面的 .. 代表当前目录里的上一级目录,也就是父级模块
self::super::super::tree1_mod1::func();
//这个函数是 tree1_mod1 中私有的不能跨mod使用
//crate::level0_mod1::tree1_mod1::fun1();
//这样也是ok的表示同级模块下的其他函数
self::func1();
}
fn func1(){
println!("This is tree2_mod1::func1");
}

1
ownership/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

8
ownership/Cargo.toml Executable file
View File

@ -0,0 +1,8 @@
[package]
name = "ownership"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

146
ownership/src/main.rs Executable file
View File

@ -0,0 +1,146 @@
use std::cmp::Ordering;
fn main() {
println!("Hello, world!");
ownership1();
ownership2();
ownership3();
ownership4();
ownership5();
}
// rust 所有权系统
// Rust 使用所有权系统来管理来自heap上的内存
// 1. 减少数据竞争,实现类似读写锁的机制
// 2. 避免提前freedouble free悬垂引用等内存问题。
fn ownership1(){
/* 对于实现了Copy trait 的类型rust会在赋值的时候直接copy一份给到新的变量
* 使使
*/
//将45绑定到num上
let num = 45;
//使用i32的Copy 将值拷贝并绑定到num1上
let num1 = num;
println!("num is {}, num1 is {}", num, num1);
/* 实现了Copy trait的类型有
* 1. i32 u32 f32 char
* stack上的Copy trait影响性能
* copy性能损失过大
*
* 访
*/
}
fn ownership2(){
/* 对于没有实现Copy trait 的类型: 同一时间只能归属于一个变量,
使shadow掉了使
使
*/
let mut str1 = String::new();
str1.push_str("This is a string");// 通过str1操作字符串添加一串字符串到String里
let mut str2 = str1; // 将所有权移交给str2
//此处String对象的所有权已经从str1移交给了str2此时已经不能再通过str1去访问(读)或者修改(写)字符串了
//str1.push_str("owner is not str1, can access string") //写
//println!("{}", str1); //读
str2.push_str("owner is str2");
println!("{}", str2);
/* 这里的String就是一个没有copy trait的类型其会在heap上申请一段内存存放字符串
* str1或者str2是在stack上的heap上
* rust通过所有权的机制
* 访
*
*/
}
fn ownership3(){
/* 所有权不仅可以移交给变量也可以通过函数参数移交给函数,但是移交给函数有一个使用上的问题:
*
*/
let mut str1 = String::new();
str1.push_str("This is a string");// 通过str1操作字符串添加一串字符串到String里
/* opt1: 如下的操作是不被允许的因为str1 所有权移交给了function join_strstr1已经不可再访问 */
//join_str(str1, "sub string");
//println!("after join str is {}", str1);
/* opt2: 只有像如下的操作将所有权从functon的返回值中再次移交回来给到一个新的变量str1才可访问字符串
* str1已经和上面的str1不一样了哦str1已经被shadow掉了
*/
let (sub_len, str1) = join_str(str1, "sub string");
println!("after join str is {}", str1);
}
fn join_str(mut str_src:String, sub_str:&str) -> (usize, String){
let len = sub_str.len();
str_src.push_str(sub_str);
(len,str_src)
}
fn ownership4(){
/* 像ownership3 所示的例子中的用法会使得复杂的数据类型在使用上会变得很麻烦,
*
*
* 使
* rust就有了引用和借用的概念
* 使
* */
let mut str1 = String::new();
str1.push_str("This is a string");// 通过str1操作字符串添加一串字符串到String里
let sub_str = 'A';
// 通过 & 将变量借用给has_char
let ret = has_char(&str1, sub_str);
match ret {
//将字符串借用给函数has_char后str1依然用拥有其所有权依然可以读写访问
true =>println!("{} has char {}", str1, sub_str),
false =>println!("[{}] has no char [{}]", str1, sub_str),
}
str1.push_str("add string after borrow");
/* 可以有多个不可变引用
*
*
*/
let str2 = &str1;
let str3 = &str1;// 可以有多个不可变引用
//str2.push_str("cant add str!"); //❎
println!("{} {} {}", str1, str2, str3);//尝试使用他们
/* 不可以同时有可变引用和不可变应用:
*
* 访
*
*/
let mut str1 = String::new();
str1.push_str("This is a string");// 通过str1操作字符串添加一串字符串到String里
//let str2 = & mut str1;
//str2.push_str("add string by borrowed mut str2");
//let str3 = &str1; //这里会报错不能同时借用给muteable和immuteable。
//println!("{} {} {}", str1, str2, str3); //在这里尝试使用三个字符串。
//{
// let str3 = &str1;
// println!("{} {}", str1, str3); //在这里尝试使用
//}
{
let str2 = & mut str1;
str2.push_str("add string by borrowed mut str2");
//str1.push_str("adas");// 不能同时读写
//println!("{} {}", str1, str2); //在这里尝试使用。
}
}
fn has_char(str_src:&String, sub_str:char) -> bool{
let idx = str_src.find(sub_str);
if idx == None{
false
}else{
true
}
}
fn ownership5(){
//
let mut str1 = String::new();
str1.push_str("This is a string");// 通过str1操作字符串添加一串字符串到String里
let str2 = &str1;
str1.push_str("add another string");
}

1
p15.smart_point/boxt/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

View File

@ -0,0 +1,8 @@
[package]
name = "boxt"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -0,0 +1,32 @@
/// # Box<T>
/// 可以理解就是void*其指向存储在堆上的内存因为RUST必须在编译器知道栈的分配
/// 但是某些数据必须是运行时动态变化的大小是不确定的所以可以将其通过box装箱
/// 使用者在使用时将其拆箱进行使用但是代码的组织上可以使用大小确定的Box<T>来占位。
pub fn learn() {
let mut num = Box::new(5);
*num = 7;
println!("num = {}", num);
/// 构造一个链表链表的每个节点存储一个i32另外一个元素是另一个节点
enum List {
//Cons(i32, List), //直接使用List会导致无限递归无法计算出List的大小
Cons(i32, Box<List>), // 使用Box将装箱使得可以实现该需求。因为Box的大小是确定
Nil,
}
let mut list = List::Cons(12, Box::new(List::Cons(13, Box::new(List::Nil))));
loop {
list = match list {
List::Cons(num, next) => {
println!("{},", num);
*next
}
List::Nil => {
break;
}
};
}
// Deref trait(Dereference operator) 解引用运算符可以通过实现Deref trait来实现在使用上智能指针像是引用一样。
}

View File

@ -0,0 +1,62 @@
/// 实现一个自定义的box类型效果和Box<T>类似,
/// 目的是为了理解Deref的意义
struct MyBox<T>(T);
impl<T> MyBox<T> {
pub fn new(item: T) -> MyBox<T> {
MyBox(item)
}
}
use std::ops::{Deref, DerefMut};
/// 手动给MyBox实现一个defref trait
impl<T> Deref for MyBox<T> {
type Target = T;
// 实现解引用返回MyBox里面包含的数据的引用
// 这样当使用*号时候就可以获得MyBox的数据了
fn deref(&self) -> &Self::Target {
&self.0
}
}
pub fn learn() {
let x = 5;
let y = MyBox::new(6);
println!("X: {}, Y:{}", x, *y); // 当MyBox实现了Deref trait的时候*y即可正确通过编译。
//Rust会自动的尝试调用Defref来获得引用看是否可以满足函数的参数要求
//这里我们使用的是MyBox类型的引用但是print_str需要的是字符串切片
//但是通过Deref 我们可以将&Mybox变为&String而String也实现了Defref所以又可以变为&str这时候就满了函数参数的要求
print_str(&MyBox::new(String::from("this is a str")));
//这种隐式的转化可以使得我们代码的可读性更好
//如果没有的话只能这样子
let temp = MyBox::new(String::from("this is a str"));
//先通过*temp进行deref获得String在通过[...]获得字符串切片
print_str(&(*temp)[..]);
//创建一个可变引用并修改其值这需要MyBox添加DerefMut trait的支持
let mut vnum = MyBox::new(4);
*vnum += 1;
//drop(vnum); // 主动调用析构函数
println!("num = {}", *vnum);
}
fn print_str(s: &str) {
println!("{}", s);
}
// 引用的转化会需要满足:当实现的 T的deref trait时 target 是U时
// 1. 可以实现T的可变引用转化为U的可变或者不可变引用
// 2. 可以实现T的不可变引用转化为U的不可变引用
impl<T> DerefMut for MyBox<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T> Drop for MyBox<T> {
fn drop(&mut self) {
println!("release a MayBox obj");
}
}

View File

@ -0,0 +1,80 @@
/// RefCell<T>
/// 相较于Rc其和Box一样只能有一个拥有者但是其可以修改内部的值Rc只能读.
pub trait Messenger {
fn send(&self, msg: &str);
}
use std::cell::RefCell;
pub struct LimitTracker<'a, T: 'a + Messenger> {
messenger: &'a T,
value: usize,
max: usize,
}
/// 为所有实现了messenger trait的类型提供一个限制检测的功能初始化时指定最大值
impl<'a, T> LimitTracker<'a, T>
where
T: Messenger,
{
pub fn new(messenger: &T, max: usize) -> LimitTracker<T> {
LimitTracker {
messenger,
value: 0,
max,
}
}
/// 这是要测试的方法该方法根据初始化时定义的max值和当前值的的比值
/// 当超过指定的比利时候发生不同的消息,没有返回值
/// 其可以被所有实现了Messenger trait的类型使用。
pub fn set_value(&mut self, value: usize) {
self.value = value;
let percentage_of_max = self.value as f64 / self.max as f64;
if percentage_of_max >= 1.0 {
self.messenger.send("超过限额")
} else if percentage_of_max >= 0.9 {
self.messenger.send("已使用90%")
} else if percentage_of_max >= 0.75 {
self.messenger.send("已使用75%")
}
}
}
#[cfg(test)]
mod tests {
use super::*;
/// 为了测试上面的LimitTracker的set_value方法这里制作一个模拟对象进行测试
/// 因为set_value本身不返回任何返回值就没法使用assert_eq等进行检测所以
/// 这里设计一个模拟对象并实现send方法在set_value函数时将发送的字符串存储起来
/// 这样跑完set_value之后我们可以通过模拟对象里面的数据来判断是否符合预期
/// 从而来获知set_value是否能够正常工作
/// 但是Messenger trait的send方法的参数是不可变引用那么在send函数里面是不可以修改成员的变量的
/// 这时候就可以使用RefCell来获得不可变引用的可变
struct MockMessenger {
sent_messenger: RefCell<Vec<String>>,
}
impl MockMessenger {
fn new() -> MockMessenger {
MockMessenger {
sent_messenger: RefCell::new(vec![]), // 使用RefCell存储数据
}
}
}
impl Messenger for MockMessenger {
fn send(&self, msg: &str) {
// borrow_mut 获得数据的可变引用
self.sent_messenger.borrow_mut().push(String::from(msg));
}
}
#[test]
fn it_sends_an_over_75_percent_wrning_messager() {
let obj = MockMessenger::new();
let mut limit_tracker = LimitTracker::new(&obj, 100);
limit_tracker.set_value(80);
// borrow_mut 获得数据的不可变引用
assert_eq!(obj.sent_messenger.borrow().len(), 1);
}
}

View File

@ -0,0 +1,28 @@
use std::rc::Rc;
/// # RC<T>
/// RC<T>: Reference counting, 是一个带有引用计数的智能指针其相较于Box来说就是可以同时被多个所有者拥有
/// 只有当所有的所有者的都生命周期结束其才会被释放。
/// RC提供的不可变引用。
pub fn learn() {
enum List {
Cons(i32, Rc<List>),
Nil,
}
// 创建一个RC list。这里为了其能够被b和c
let mut a = Rc::new(List::Cons(2, Rc::new(List::Cons(4, Rc::new(List::Nil)))));
// 通过Rc::clone将数据的智能指针copy一份内容还是一样的
let b = List::Cons(3, Rc::clone(&a));
println!(
"strong ref of a is {}, weak is {}",
Rc::strong_count(&a),
Rc::weak_count(&a)
);
let c = List::Cons(3, Rc::clone(&a));
println!(
"strong ref of a is {}, weak is {}",
Rc::strong_count(&a),
Rc::weak_count(&a)
);
}

View File

@ -0,0 +1,9 @@
/* 智能指针,是一个概念,其智能本质上是来自于计数的检查,只是交给了编译器去处理销毁的时机,
使double free的问题
*/
pub mod SmartPoint {
pub mod BoxT;
pub mod my_box;
pub mod rc_cell_t;
pub mod rc_t;
}

View File

@ -0,0 +1,47 @@
fn main() {
println!("Hello, world!");
smart_point_learn();
}
use std::cell::RefCell;
use std::rc::{Rc, Weak};
use boxt::SmartPoint::my_box;
use boxt::SmartPoint::rc_t;
use boxt::SmartPoint::BoxT;
fn smart_point_learn() {
BoxT::learn();
my_box::learn();
rc_t::learn();
#[derive(Debug)]
struct StNode {
data: String,
//使用weak可以使得指向parent并非强引用不会影响parent的释放
parent: RefCell<Weak<StNode>>,
//使用rc可以使得强引用子节点只有父节点不再持有时才可释放
child: RefCell<Vec<Rc<StNode>>>,
}
let leaf = Rc::new(StNode{
data: String::from("leaf"),
parent: RefCell::new(Weak::new()),
child: RefCell::new(vec![]),
});
println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
let root = Rc::new(StNode{
data: String::from("root"),
parent: RefCell::new(Weak::new()),
child:RefCell::new(vec![leaf.clone()]),
});
*(leaf.parent.borrow_mut()) = Rc::downgrade(&root);
println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
println!("root strong ref {}, weak ref {}", Rc::strong_count(&root), Rc::weak_count(&root));
println!("leaf strong ref {}, weak ref {}", Rc::strong_count(&leaf), Rc::weak_count(&leaf));
drop(root);
println!("leaf strong ref {}, weak ref {}", Rc::strong_count(&leaf), Rc::weak_count(&leaf));
println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
// println!("tree is {}", root);
}

1
p16.fearless_conscurrency/mutex/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

View File

@ -0,0 +1,8 @@
[package]
name = "mutex"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -0,0 +1,33 @@
fn main() {
println!("Hello, world!");
mutex_learn();
}
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
fn mutex_learn() {
let strings = Arc::new(Mutex::new(vec![]));
let mut ths = vec![];
for i in 1..10 {
let strings = Arc::clone(&strings); //获得一个强引用
let handle = thread::spawn(move || {
for _i in 1..3 {
strings
.lock()
.unwrap()
.push(String::from(format!("thread{}: ", i)) + &(i + _i).to_string());
thread::sleep(Duration::from_micros(
(((1 as f64) / (i as f64)) * 100.0) as u64, //线程越前的睡的越久
));
}
});
ths.push(handle);
}
for th in ths {
th.join().unwrap();
}
println!("strings is {:?}", strings.lock().unwrap());
}

View File

@ -0,0 +1 @@
/target

View File

@ -0,0 +1,8 @@
[package]
name = "shared_trait"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -0,0 +1,51 @@
//定义一个Draw trait所有实现了Draw trait的类型都要具有draw方法。
pub trait Draw {
fn draw(&self);
}
pub struct Screen {
pub components: Vec<Box<dyn Draw>>,
}
impl Screen {
pub fn new() -> Screen {
Screen { components: vec![] }
}
pub fn add(&mut self, comp: Box<dyn Draw>) {
self.components.push(comp)
}
pub fn run(&self) {
if self.components.len() == 0 {
println!("has no components!");
return;
}
for obj in self.components.iter() {
obj.draw();
}
}
}
pub struct Button {
width: u32,
height: u32,
text: String,
}
impl Button {
pub fn new(width: u32, height: u32, text: &str) -> Button {
Button {
width,
height,
text: String::from(text),
}
}
}
impl Draw for Button {
fn draw(&self) {
println!(
"This is a Button, draw by {}x{} : {}",
self.width, self.height, self.text
);
}
}

View File

@ -0,0 +1,32 @@
use shared_trait::*;
struct SelectBox<'a> {
width: i32,
height: u32,
option: Vec<&'a str>,
}
impl<'a> Draw for SelectBox<'a> {
fn draw(&self) {
println!(
"This is a Button, draw by {}x{} : {:?}",
self.width, self.height, self.option
);
}
}
fn main() {
println!("Hello, world!");
let mut screen = Screen::new();
let button = Button::new(30, 40, "Button text");
screen.add(Box::new(button));
screen.add(Box::new(SelectBox {
width: 100,
height: 300,
option: vec!["option1", "option2", "option3"],
}));
// screen.add(Box::new(String::from("asdad"))); //the trait bound `String: shared_trait::Draw` is not satisfied
screen.run();
}

1
p16.fearless_conscurrency/thread/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

View File

@ -0,0 +1,8 @@
[package]
name = "thread"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -0,0 +1,98 @@
fn main() {
println!("Hello, world!");
thread_learn();
thread_learn1();
thread_learn2();
}
use std::thread;
use std::time::Duration;
fn thread_learn() {
let handle = thread::spawn(|| {
for i in 1..5 {
println!("thread {}", i);
thread::sleep(Duration::from_millis(100));
}
});
for i in 1..5 {
println!("main {}", i);
thread::sleep(Duration::from_millis(50));
}
handle.join().unwrap();
}
fn thread_learn1() {
let v = vec![1, 2, 3, 4];
//闭包是可以直接捕获上下文中的变量并使用的但是在线程里不行。因为rust无法获知线程合适结束也就
//无法保证v的有效性。如果需要在threa里使用主线程中的变量。需要使用move将其移动到子线程
//这样主线程也就不在拥有v的所有权了
/* 这种方式会编译不过。因为v不可以再子线程使用 */
// let handle = thread::spawn(|| {
// println!("thread {:?}", v);
// });
// println!("main {:?}", v);
/* 这种方式会编译不过。因为v被移动到子线程主线程已不可使用 */
let handle = thread::spawn(move || {
println!("thread {:?}", v);
});
//println!("main {:?}", v);
handle.join().unwrap();
}
use std::sync::mpsc;
fn thread_learn2() {
let (tx, rx) = mpsc::channel();
let tx1 = mpsc::Sender::clone(&tx); //再产生一个生产者
let handle = thread::spawn(move || {
let val = String::from("hello");
tx.send(val).unwrap();
let msgs = vec!["aaaa", "qwer", "rty", "byebye", "zaas"];
for msg in msgs {
match tx.send(String::from(msg)) {
Err(err) => {
println!("发送失败 {:?}", err);
break;
}
_ => {}
}
thread::sleep(Duration::from_micros(20));
}
});
let thandle1 = thread::spawn(move || {
let val = String::from("hello");
tx1.send(val).unwrap();
let msgs = vec!["aaaa1", "qwer1", "rty1", "byebye1", "zaas1"];
for msg in msgs {
match tx1.send(String::from(msg)) {
Err(err) => {
println!("发送失败 {:?}", err);
break;
}
_ => {}
}
thread::sleep(Duration::from_micros(5));
}
});
let handle1 = thread::spawn(move || loop {
let val = match rx.try_recv() {
Ok(msg) => msg,
Err(_) => {
thread::sleep(Duration::from_millis(10));
continue;
}
};
// let val = rx.recv().unwrap();
if val == "byebye" {
drop(rx);
break;
}
println!("receive a msg: {}", val);
});
handle.join().unwrap();
thandle1.join().unwrap();
handle1.join().unwrap();
}

1
p18.match/match_learn/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

View File

@ -0,0 +1,8 @@
[package]
name = "match_learn"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

107
p18.match/match_learn/src/main.rs Executable file
View File

@ -0,0 +1,107 @@
use std::{env::var, sync::atomic::AtomicI32, vec};
fn main() {
println!("Hello, world!");
learn();
}
struct Point {
x: i32,
y: i32,
}
fn learn() {
let var = 3;
match var {
//@绑定val使用..匹配一些值
val @ 1..=4 => println!("match 1..4, {}", val),
_ => println!("match"),
}
let mut var = vec![1, 2, 3, 4, 5, 6, 7];
while let Some(var) = var.pop() {
match var {
//@绑定val使用|来进行多重匹配
val @ (1 | 3 | 5) => println!("match 1,3,5 => {}", val),
_ => println!("miss match val {}", var),
}
}
let mut var = vec![1, 2, 3, 4, 5, 6, 7];
let cond = 2;
while let Some(var) = var.pop() {
match var {
//使用if语句来进行进一步的限制b不满足条件的同样会走到其他分支
val @ (1 | 3 | 5) if val > cond => println!("match 1,3,5 > {} => {}", cond, val),
val @ (1 | 3 | 5) => println!("match 1,3,5 <= {} => {}", cond, val),
_ => println!("aa miss match val {}", var),
}
}
let var = vec!["first", "second", "third", "fourth", "last"];
match var[..] {
[last, .., end] => println!("start str is {}, end str is {}", last, end),
_ => {}
}
let var = ("first", "second", "third", "fourth", "last");
// let var = ("first", "second", "third", "fourth", "end");
match var {
(last, .., "last") => println!("a str end by \"last\", start str is {}", last),
_ => println!("not match a tuple end with \"last\""),
}
//let var = (12, "string");
let var = (123, "string");
match var {
(x, y) if x == 12 => {
println!("fist is 12, second is {}", y);
}
(x, y) => {
println!("fist is not 12 but {}, second is {}", x, y);
}
}
//解构元组
let var = (123, "string");
let (x, y) = var;
println!("after x:{}, y{}", x, y);
//解构结构体
let var = Point { x: 23, y: 34 };
let Point { x, y } = var; //解构时成员明明必须相同
println!("after x:{}, y{}", x, y);
//区间匹配
let c = 'c';
match c {
'a'..='z' => {
println!("is a lower char");
}
'A'..='Z' => {
println!("is a upper char");
}
'0'..='9' => {
println!("is a number");
}
_ => {
println!("other char");
}
}
let var = Point { x: 23, y: 34 };
deconstruct((23, 34), ((45, 23423), var));
//可以通过元组将结构体和元组嵌套进行解构
//使用_开头的变量即使未使用也不会导致编译器警告。
let var = Point { x: 23, y: 34 };
let ((_w, _z), Point { x, y }) = ((12, 34), var);
//_不会绑定变量转移所有权所以再使用_后所有权还是在原变量上
let var = Some(String::from("strzzzz"));
if let Some(_) = var {
println!("find a string");
}
println!("str is {:?}", var);
}
fn deconstruct((h, t): (i32, i32), ((w, r), Point { x, y }): ((i32, i32), Point)) {
println!("h:{},t:{}, w:{},r:{},x:{},y:{},", h, t, w, r, x, y);
}

1
panic_except/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

8
panic_except/Cargo.toml Executable file
View File

@ -0,0 +1,8 @@
[package]
name = "panic_except"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

0
panic_except/hello_word.txt Executable file
View File

1
panic_except/name.txt Executable file
View File

@ -0,0 +1 @@
Ekko.bao

181
panic_except/src/main.rs Executable file
View File

@ -0,0 +1,181 @@
use std::{fs::File, io::{self, ErrorKind, Read}, net::IpAddr};
fn main() {
println!("Hello, world!");
/* panic 属于不可恢复的错误 */
//主动触发一个panic
// panic!("crash and burn!")
//在panic的时候控制台会输出很多信息我们可以根据这些信息来获知崩溃的位置。以及调用链
//我们可以设置一些环境变量来决定信息的多少:
// set RUST_BACKTRACE=0 关闭触发异常时的堆栈回溯。仅显示崩溃信息
// set RUST_BACKTRACE=1 打开堆栈回溯
// set RUST_BACKTRACE=full 显示特别详细的堆栈回溯信息
//访问其他代码触发异常 比如这里访问越界。会在vec的代码里面发生panic
/* thread 'main' panicked at src\main.rs:9:23:
index out of bounds: the len is 3 but the index is 99
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
*/
// let var = vec![1,2,3];
// println!("{}", var[99]);
/* 在代码编写中可能会有一些异常的参数值或者状态出现在代码运行时这时候我们应该处理这些值避免进一步蔓延甚至导致panic的发生
RUST中是没有异常的捕获处理方式的
Result枚举来进行错误的承载和处理
coding过程中应该按照
1.
2. Result枚举
3. 使panic进行终止程序
*/
//尝试打开一个文件因为文件不一定会能够打开失败所以这里返回值Result类型我们必须要进行处理
let f = File::open("hello_word.txt");
//这里使用match 表达式进行处理, 保证f一定是可用的
let mut f = match f{
Ok(file) => file,// 成功-> 将文件对象作为match表达式的值进行返回
Err(error) => {
//这里根据错误的类型进行处理。
match error.kind() {
//如果文件不存在则尝试创建一个空文件, 并返回
ErrorKind::NotFound => match File::create("hello_word.txt") {
Ok(file) => file,
Err(error) => panic!("{}", error),//创建失败错误直接panic
}
//其他类型错误直接panic
_ => panic!("{}", error),
}
}
};
/*
Result的返回值可以使得
:
open失败的情况根据错误的类型进行差异化的处理open file的区块才算结束
使
match不断的嵌套是一件很痛苦的处理过程
*/
//如果代码能走到这里说明f一定是可用的状态
let mut buff = String::new();
let _ = f.read_to_string(&mut buff);
println!("file conext is [{}]", buff);
//对比上面的方式,下面这个函数的处理方式就是如果失败了返回到调用者使其进行
//决断确定错误的处理方式避免在函数内进行panic的情况。
match read_username_from_file() {
Ok(name) => println!("name is {}", name),
Err(error) => println!("err happend! {}", error),
}
/* 但是即使是将错误进行传播也需要大量的match 表达式进行匹配并处理,
RUST提供了一个专门的运算符 ? match代码的代码量
使
*/
match read_username_from_file1() {
Ok(name) => println!("name is {}", name),
Err(error) => println!("err happend! {}", error),
}
//使用链式调用减少代码,可见如下函数的实现
match read_username_from_file2() {
Ok(name) => println!("name is {}", name),
Err(error) => println!("err happend! {}", error),
}
// 其他的Result处理方式
other_panic();
}
//定义一个函数返回值类型是Result
fn read_username_from_file() -> Result<String, io::Error> {
/* 这里演示了一种传播错误的方法我们通过将函数的返回值定义为Result的方式
*/
let f = File::open("name.txt");
let mut f = match f {
Ok(file) => file,
//如果打开失败了那么就将失败的错误传播回去
Err(error) => return Err(error),
};
let mut buff = String::new();
match f.read_to_string(&mut buff) {
//如果读取失败了则也是返回一个错误
Err(error) => return Err(error),
Ok(size) => {
//如果size为0主动构造一个错误进行返回
if size == 0 {
return Err(io::Error::new(io::ErrorKind::Other, "File is empty"));
}
},
}
Ok(buff)
}
//这是将read_username_from_file使用 ? 运算符进行简化之后的实现
fn read_username_from_file1() -> Result<String, io::Error> {
/* ? 表达式可以使得当错误发生时将错误进行Return
使
?Result或者option为返回值的函数才能够使用
*/
let mut buff = String::new();
let mut f = File::open("name.txt")?;// ? 运算符
let size = f.read_to_string(&mut buff)?;// ? 运算符
if size == 0 {
return Err(io::Error::new(io::ErrorKind::Other, "File is empty"));
}
Ok(buff)
}
//使用链式调用进一步简化代码
fn read_username_from_file2() -> Result<String, io::Error> {
/* 因为使用了?运算符可以保证如果函数可以走到后续的代码说明一定是成功了的
使
使使
*/
let mut buff = String::new();
if File::open("name.txt")?.read_to_string(&mut buff)? == 0 {
return Err(io::Error::new(io::ErrorKind::Other, "File is empty"))
}
Ok(buff)
}
fn other_panic() {
/* 除了主动的panic宏来进行错误检测后的主动panic。我们还有另外的panic的方式: unwrap 和 except
unwrap可以在结果为Err或者为None的时候发生panic
except可以附加一些信息
西match表达式检测异常?
1.
2.
3.
使Result的函数接口的时候就可以使用这两个方法进行结果的检测和处理
*/
//我们如果知道这一定是不可能会失败的那么我们可以用unwrap来进行结果的提取而不必理会
//比如这里我们明确他是一个常量的合法的IP地址那么就直接使用unwrap来提取即可
let ip:IpAddr = "127.0.0.1".parse().unwrap();
//他和下面这样是一样的效果,但是我们知道不可能失败错误就没必要这么复杂了
// let ip:IpAddr = match "127.0.0.1".parse() {
// Ok(ipaddr) => ipaddr,
// Err(error) => panic!(),
// };
//这是使用except的方式可以添加一些信息
let ip:IpAddr = "127.0.0.1".parse().expect("解析ip地址失败了");
}
/* 可以看出Rust在对于错误的处理的安全上也是及其苛刻的
使
使Result来将错误不隐藏
?
*/

1
string_learn/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

8
string_learn/Cargo.toml Executable file
View File

@ -0,0 +1,8 @@
[package]
name = "string_learn"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

58
string_learn/src/main.rs Executable file
View File

@ -0,0 +1,58 @@
fn main() {
println!("Hello, world!");
string_learn();
}
fn string_learn() {
//字符串字面值 类型:&str
let str1 = "this is a &str";
//从字符串字面值创建一个string类型String
let str2 = String::from("hello");
//字符串引用。 类型: &string
let str3 = &str2;
//字符串切片 类型:&str
let str3_1 = &str2[0..2];
//拼接字符串
let str4 = String::from("world");
//let str5 = str2 + str4;//这是不允许的,+ 右边必须是字符串的切片或者字符串字面值
let str5 = str2 + &str4; //经过这句之后 str2 的所有权已经移交到 + 的实现函数里面了,使用后就被释放了。
//使用format 宏去连接字符串
let str6 = format!("{}{}", str5, "aaa");
//字符串不允许使用下标进行访问:
//rust的字符串是unicode编码的每个“字母”所占用的byte数是不等长得。
println!("长度为 {}", "中文".len());//这里的结果应该是6每个中文占三个字节
println!("长度为 {}", "AB".len());//这里的结果应该是2每个ascii占1bytes
/* 除此之外,还有很多其他的国家、文化的语言,可能是多个字母才能表达一个意思的,还有的是逆序的
unicode标量值
*/
//获取字符串对应的内存数据
let buff = "中文".bytes();
print!("中文 bytes is [");
for it in buff {
print!("{} ", it);
}
println!("]");
//当我们使用字符串切片的获取一部分内容的时候需要额外小心,
//每种语言其char的大小是不一样的所以如果获取的内容处于两个char之间就会panic
let s = &"中文"[0..3];
println!("字符串切片 中文[0..3] is {}", s);
//let s = &"中文"[0..2];//一个中文char占用3byte这里只取了两个byte就会panic
//遍历所有char可以用chars方法
print!("遍历所有char [");
for it in "这是一个中文+表情💚DE字符串".chars() {
print!("{} ", it);
}
println!("]");
//println!("char0 is {}", "adb"[0]); //默认不支持根据索引进行获取因为无法保证能够获取到一个有效的unicode标量值 char
}

1
struct_learn/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

8
struct_learn/Cargo.toml Executable file
View File

@ -0,0 +1,8 @@
[package]
name = "struct_learn"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

170
struct_learn/src/main.rs Executable file
View File

@ -0,0 +1,170 @@
fn main() {
println!("Hello, world!");
struct01();
let user = build_user(String::from("qwer"), String::from("ertyfd"));
println!("user info name:{}, age:{}, email:{}", user.name, user.age, user.email);
let user1 = ref_build_use1(user);
println!("user1 info name:{}, age:{}, email:{}", user1.name, user1.age, user1.email);
sturct_empty();
tuple_struct();
struct_method_test();
}
fn struct01()
{
//定义一个结构体类型使用struct为关键字后面跟其名字
//定义成员,类型后置,每个成员定义后都需要使用逗号分隔
struct User{
name:String, //类型后置,逗号分隔
email:String,
age:i32,
is_man:bool,
sign_cnt:i64, //最后一个成员也需要加逗号
} //无需使用分号
// 使用指定的类型初始化一个实例,每个成员都必须进行初始化赋值。
let mut user = User{
name:String::from("ekko.bao"),
email:String::from("yucang_bao@126.com"),
age:8,
is_man:true,
sign_cnt:2222222,
};
//访问成员使用点分隔符进行访问
println!("user info name:{}, age:{}, email:{}", user.name, user.age, user.email);
//struct所有成员mut是整体的不可单个设置要么所有都可被修改要么都不可被修改。
user.age = 888;
}
struct User{
name:String, //类型后置,逗号分隔
email:String,
age:i32,
is_man:bool,
sign_cnt:i64, //最后一个成员也需要加逗号
}
fn build_user(name:String, email:String) -> User {
// 这里展示了一种初始化struct的简便方法
User{
name, //等效于 name:name 当想要初始化的成员名和变量名一致时可直接省略赋值操作
email,//等效于 name:email
age:10,
is_man:false,
sign_cnt:66666,
}
}
fn ref_build_use1(user1:User) -> User {
// 这里展示了一种初始化struct的简便方法
// 当我们一部分内容想要自定义初始化一部分来自另外一个stuct
// 那么我们可以使用如下的语法进行
User{
/* 填写自定义初始化的内容 */
name:String::from("user1.bao"),
email:String::from("zzzzzzz@126.com"),
age:77,
/* 选择继承已有结构体,未初始化的其他成员将会使用该结构体进行初始化
*/
..user1
}
}
fn sturct_empty(){
// stuct可以是空成员的这个是为了只实现一些方法但是不提供成员数据的应用场景。
struct empty_struct{
}
let test = empty_struct{};
}
fn tuple_struct(){
// tuple struct 是类似元组的struct没有成员名只有类型。
// 使用括号进行包裹所有成员
struct RGB(u8,u8,u8);
let color = RGB(34,233,123);
println!("color is R:{} G:{} B:{}", color.0, color.1, color.2);
struct POINT(u8,u8,u8);
let point = POINT(34,233,123);
println!("point is X:{} Y:{} Z:{}", point.0, point.1, point.2);
// let point:POINT = color; // color和point虽然成员的类型和个数都是一样的但是是不同的类型所以不可以进行绑定
let color1 = RGB{0:23,..color};//同样可以使用这种继承部分成员的赋值方法
println!("color1 is R:{} G:{} B:{}", color1.0, color1.1, color1.2);
let color2 = color1; //color1 所有权移交给color2 color1不可在使用
println!("color2 is R:{} G:{} B:{}", color2.0, color2.1, color2.2);
//println!("color1 is R:{} G:{} B:{}", color1.0, color1.1, color1.2);//不可使用
}
//注解 ,可以打印结构体内容
#[derive(Debug)]
struct Rectangle {
width: i32,
height: i32,
}
//定义结构体Rectangle的实现
impl Rectangle{
/* 第一个参数为self的是该结构体的方法 就类似于类的成员函数 */
//求长方形面积
fn area (&self) -> i32{ // 使用引用的方式使用self, 可以不显式的标注类型
//fn area (self: &Rectangle) -> i32{ // 使用类型后置标注的方式也是ok的
//fn area (self: & mut Rectangle) -> i32{ // 也可以接上mut关键字 这使得可以修改成员变量
// self.width = self.height;
//fn area (self: Rectangle) -> i32{ // 非引用的方式使用也是ok的但是要注意所有权的问题
self.width * self.height
}
/* 第一个参数不是self的是该结构体的关联函数 */
fn new(width: i32, height: i32) -> Rectangle{
Rectangle{
width,
height,
}
}
}
//impl可以分布在多个地方。只需要进行impl包裹即可
impl Rectangle{
//根据传入的矩形创建一个外接的正方形
fn create_hold_square(other:&Rectangle) -> Rectangle{
let width = if other.width > other.height {other.width} else {other.height};
Rectangle{
width,
height: width,
}
}
//检查一个矩形是否可以完全按包住另一个矩形
//像这样类型后置的申明self的类型的方式也是可以的
fn can_hold(self: &Rectangle, other:&Rectangle ) -> bool{
if self.width >= other.width && self.height >= other.height {
true
}
else{
false
}
}
}
fn struct_method_test(){
//使用关联函数初始化一个矩形
let rect = Rectangle::new(30,30);
println!("rect is{:#?}, area is {}", rect, rect.area());
let rect = Rectangle{
width: 60,
height: 40,
};
let rect1 = Rectangle::create_hold_square(&rect);
println!("rect is {:?}, rect1 is {:?}", rect, rect1);
println!("rect1 {} hold rect", if rect1.can_hold(&rect) {"can"} else {"can not"});
}

1
trait_learn/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

8
trait_learn/Cargo.toml Executable file
View File

@ -0,0 +1,8 @@
[package]
name = "trait_learn"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

116
trait_learn/src/lib.rs Executable file
View File

@ -0,0 +1,116 @@
/* 我们设计一个summary trait我们希望这个trait可以提供一个摘要的功能
便
*/
pub trait Summary {
//定义一个summary trait下的方法 summerize该方法返回一个摘要的字符串
fn summarize(&self) -> String;
/* trait 定义得到每个方法在使用了impl trait的数据结构中都需要完整实现所有的方法 */
//fn reply(&self) -> bool; // 比如定义了这个方法后下面引入了Summary的NewsArticle和Tweet都需要进行实现
// 定义一个author方法并将其实现这就是trait的默认方法
// 如果引入了summary的数据结构没有实现该方法那么在调用时就会调用该默认方法。
fn author(&self) -> String {
String::from("unkown")
}
}
// 定义一个新闻文章的数据结构,
pub struct NewsArticle {
pub headline:String, // 标题
pub location:String, // 地点
pub author: String, // 作者
pub content:String, // 内容
}
//定义一个推文的数据结构
pub struct Tweet {
pub username:String,//用户名
pub content:String, // 内容
pub reply: bool, //是否可回复
pub retweet:bool, //是否可转发
}
//为 NewsArticle 实现 summary
// 语法为 impl <trait name> for <data_type>
impl Summary for NewsArticle {
fn summarize(&self) -> String {
//对于新闻来说我们使用标题,作者和地点。生成一个摘要信息
format!("{}, by {} ({})",self.headline, self.author(), self.location)
}
//覆盖掉Summary的默认author实现。在NewsArticle 实例调用该方法时只能调用到该函数,
//并且该函数无法再调用到默认的author函数
fn author(&self) -> String {
let mut one = String::new();
self.author.clone_into(&mut one);
one
}
}
impl Summary for Tweet {
fn summarize(&self) -> String {
//对于推文来说我们使用作者和推文内容作为摘要
format!("{}: {}", self.author(), self.content)
}
}
/* 经过上面针对两种不同的数据结构对于summery的实现
使->
*/
// 通过引入Dsiplay trait来使得本地的数据结构Tweet具备 Display的功能
use std::{fmt, fmt::{Display, Formatter}};
impl Display for Tweet {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
//实现Display trait的功能
write!(f, "{}:\n {} \n reply:{} retweet:{}", self.username, self.content, self.reply, self.retweet)
}
}
/*
RUST提供了另外一种限制参数类型的方式impl trait
使trait的类型才可以使用该函数
使trait所做的功能使trait的类型都可以免于实现类似的函数
var: impl xxx
*/
//定义一个通知函数。只有具备summary trait的类型才可以作为参数传递进来。
//这样的一个通用的通知函数,使得不用为每个想要通知的数据类型都写一个类似的函数
pub fn notify(not: impl Summary){
println!("new notification: [{}]", not.summarize());
}
// 传入两个参数都用impl Summary修饰表示not1和not2都是实现了Summary的类型但是他们不一定是同一个数据类型。
pub fn notify1(not1: impl Summary, not2: impl Summary){
println!("new notification1: [{}]", not1.summarize());
println!("new notification1: [{}]", not2.summarize());
}
// 传入两个参数都都是类型TT类型要求是符合Summary trait的类型,
// 这里要注意not1和not2都必须是同一种类型才可以
pub fn notify2<T: Summary>(not1: T, not2: T){
println!("new notification2: [{}]", not1.summarize());
println!("new notification2: [{}]", not2.summarize());
}
//要求参数同时满足多个trait的类型限制
pub fn some_func0<T: Summary+Copy>(not1: T){
}
//多个参数每个参数各自限制不用的trait限制
pub fn some_func<T: Summary+Copy, U: Summary + Display>(not1: T, not2: U){
}
//简化的写法使用Where来将限制提在函数签名外使得函数名和参数列表比较靠近where可以换行多行来写
pub fn some_func1<T, U>(not1: T, not2: U) -> i32
where T: Summary+Copy, U: Summary + Display
{
0
}
// 返回值同样可以限制为实现了某个trait的数据类型, 也可以多种trait限制叠加。
// 返回一个实现了Summary trait和Copy类型的变量
pub fn some_func2<T, U>(not1: T, not2: U) -> impl Summary+Copy
where T: Summary+Copy, U: Summary + Display
{
not1
}

137
trait_learn/src/main.rs Executable file
View File

@ -0,0 +1,137 @@
use core::num;
use trait_learn::{self, NewsArticle, Summary, Tweet};
fn main() {
println!("Hello, world!");
trait_learn();
largest_test();
displaytest();
}
/* traitRUST中实现一些接口或者特性或者共享功能的机制
C中我们一般对外提供功能都是使用的一个头文件去申明接口lib
lib里
rust来说pub关键字进行暴露的trait是做什么用呢
trait是在接口之上的一个东西
trait后trait的数据结构他们在某种程度上就是有一种共同的功能
使使
print, Display这个trait的数据结构都进行打印到终端
Display trait实现print函数
Display来说C++<<python中重载了 _str_()
trait这个概念领出来呢使
trait还可以作为参数的限制的一部分
C++type list来限制list里面的类型才可以传入这个函数,
template<T>
typename enable_if<xxx>
RUST是倒过来进行筛选trait的类型才可以被调用
T: impl xxx
xxx的数据类型进行修改该函数的代码
*/
fn trait_learn() {
// 定义一个 新闻实例
let news = NewsArticle {
author: String::from("ekko.bao"),
content: String::from("Th ShangHai Peenguins once again are the best hockey team in the NHL."),
headline: String::from("Penguins win the stanley Cup Championship"),
location: String::from("ShangHai, China"),
};
// 定义一个tweet实例
let tweet = Tweet {
username: String::from("ekko.bao"),
content: String::from("of course, as you probably already know, people."),
reply: false,
retweet: false,
};
println!("1 new tweet: {}", tweet.summarize());
println!("New article: {}", news.summarize());
// 对于实现了 Display的类型可直接进行打印
println!("tweet:{}", tweet);
//NewsArticle未实现Diaply trait无法进行打印。
//println!("article:{}", news);
//可以使用 notify ,因为 Tweet 和 NewsArticle 都实现了 Summary
//trait_learn::notify(tweet);
//trait_learn::notify(news);
//无法使用notifythe trait bound `&str: Summary` is not satisfied
//trait_learn::notify("new notify");
// news和tweet 并不是同一种类型.是不可以调用的 notify2的
//trait_learn::notify2(news, tweet);
// news和tweet 都实现了Summary,可以调用notify1
trait_learn::notify1(news, tweet);
}
/*
trait crate trait是在src/lib.rs里面定义的所以
impl也只能在lib.rs里面进行实现main.rs里面实现
使lib的时候恶意破坏lib的代码
*/
// impl Summary for NewsArticle {
// }
//使用trait限制只有实现了比较和拷贝的类型才可以call largest函数
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
let mut lag = list[0];
for &item in list.iter() {
if lag < item { // PartialOrd trait
lag = item; // Copy trait
}
}
lag
}
fn largest_test() {
let number_list = vec![24, 50, 35, 100 ,65];
let result = largest(&number_list);
println!("largest is {}", result);
}
struct Point {
x:i32,
y:i32
}
use std::fmt;
impl fmt::Display for Point{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
pub trait AddStr {
fn add_str(&self) -> String;
}
// 为所有支持dispaly trait类型添加一个对于AddStr的支持
// AddStr 这个示例trait的目的是为了加一个前导的字符串
impl <T> AddStr for T
where T: fmt::Display
{
fn add_str(&self) -> String{
String::from("head str") + &self.to_string()
}
}
fn displaytest(){
let var = Point{
x:12,
y:12,
};
let str = var.to_string();
let str1 = var.add_str();
println!("{} -> {}", str, str1);
}

1
variable/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

8
variable/Cargo.toml Executable file
View File

@ -0,0 +1,8 @@
[package]
name = "variable"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

117
variable/src/main.rs Executable file
View File

@ -0,0 +1,117 @@
//学习不可变变量可变变量const变量类型标注
//const变量在函数外函数内都可以定义必须加上类型标注
const MAX_POINT:i32 = 90;
//rust 是静态强类型,编译时语言
fn main() {
const MAX_POINT:u32 = 999;
//申明一个不可变变量
let immute_var:&str = " ";
//如下使用将会报错,因为给不可变变量二次赋值
//immute_var = "qwer";
//重新使用let关键字可以使得用一个同名的一个不可变变量之前的变量就被shadow掉了
let immute_var = "aasd";
//同理可以修改变量的类型,因为这其实是一个新变量
let immute_var:u32 = 90;
//定义一个可变变量
let mut mute_var = 78;
//给可变变量重新绑定一个新的值
mute_var = 45;
//不可以修改变量类型, 静态强类型!
//mute_var="asdasd"
data_type();
compound();
array()
}
fn data_type(){
//变量类型:
//变量类型分为标量类型和复合类型:
/*
i8 i16 i32 i64 i128
u8 u16 u32 u64 u128
f32 f64
i32和f64
bit位有关系
*/
//类型标注
let num:u16= 666;
//数据后后置类型
let num= 0x1234u16;
//支持多种赋值方式
let num= 0x1234;//16进制
let num= 1234; //10进制
let num= 1_234_234;//下划线分割,增强可阅读性
let num= 0b1111_0000;//二进制
let num=0o123_675;//8进制
//使用ASCII的值进行复制仅限u8类型
let num = b'A';//
let num:u8 = b'|';//
//let num:u16 = b'A';//报错类型不匹配
//数据溢出,进行环绕,
//let num:u8 = 255 + 1; // => num = 0
//println!("255+1 = {}", num);
//强类型不可以从i32->f32直接赋值
//let num1:f32 = num;
//定义一个字符变量Unicode变量四个bytes。和字符串不同他是单引号的
let c:char='A';
let c:char='我';
let c:char='😍';
//定义布尔类型,占一个字节
let ok=true;
let ok=false;
//和架构有关的类型 isize usize, 在多少位的系统上就是多少位的
let num:isize=78;
let num:usize=34;
}
//复合数据类型
fn compound(){
//定义一个元组每个元组元素各不相同
let tup = ("123", '👀', 34, 45.6f32, b'A', 0x45u16, 0o34);
//定义一个元组指定数据类型
let tup:(i32,u8,u16) = (1,1,1);
//解构元组
let (x,y,z) = tup;
println!("{} {} {}", x, y, z);
//下标获取元组元素
let x = tup.0;
let y = tup.1;
let z = tup.2;
//越界访问,编译时即会报错!
//let z = tup.3;
println!("{} {} {}", x, y, z);
}
fn array(){
//定义一个数组,数组元素数据类型必须完全一致
let ary = [1,2,3,4];
//不仅是数字,可以是任意数据类型
let ary = ['💕', '😢', 'A'];
//指定数据类型和长度,并初始化
let mut ary:[char;3] = ['🙌';3];
println!("before {} {} {}", ary[0], ary[1], ary[2]);
//使用索引修改数组元素
ary[0] = '💕';
println!("after {} {} {}", ary[0], ary[1], ary[2]);
//越界访问编译报错, 这个检查不一定的可靠的,有可能在逻辑复杂时无法检测到
//println!("test {} {} {} {}", ary[0], ary[1], ary[2], ary[3]);
}

1
vector_learn/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target

Some files were not shown because too many files have changed in this diff Show More