前言

我自己的语言语言学习树

最新的新闻

 最近的新闻,Rust 审核团队,集体辞职抗议, 还是linux 社区的 linus 牛皮,镇得住场子不要慌,咱们是在linux 社区混的,影响不大,该学还是得学

先下个蛋, 再说,关键问题是内存模型差异巨大, 如果是纯软件,用就用了,驱动编程的接口就很尬,别慌慢慢来

  • 做linux 嵌入式开发的话,就拿语言来讲,基本上是完整的, 可以对标linux 社区
  • 为什么这样说,内核的调试开发引入了,python BCC 工具,目前是用的最多的
  • C++ 在不考虑模板编程的情况下,和C 差异不大,但是算法提供的多,现成的数据结构也多,同时熟悉面向对象可以对内核编程有帮助
  • Rust 现在小众,但是这个语言,在linux 社区里面 很火,他和C++ 的语法 相差不大,如果C++ 足够熟得话,学习成本较低
  • 这3门语言,如果做Linux 嵌入式,主要是别人都会
  • 在看脚本,为了简化工作量,单纯的人工测试,虽然没有运维的水平高,但是简化工作量,还是可以做到的,别人都会
  • 工程管理,在linux gnu 开源代码里,用的是 Makefile,但是 大多是 autoconf ,生成的,或者 cmake,但是cmake 语法简单,学习成本低,主要是别人都会
  • 日常工作, Markdown 可以快速生成pdf ,在有pdf 转化成 word 也可以 ,说明什么问题清楚明了,也主要是别人都会
  • 完全不会的那些,stap 还好,ARM 不是难,是记忆的地方多,而且,得经常用,matlab 做个数据计算啥的方便,可以模拟一些基本电路,也不是难,关键是数学计算,现在忘的差不多了
  • 可有可无系列,没啥意思的时候,可以鼓捣,如果不是专门做,我也不建议做,入门容易,但是非常熟练,得花大量时间,好玩是好玩,但是耗时间
  • 算法训练,其实是重要,但是,有专门的算法岗,我不太清楚,日常和算法相关的很少,就算涉及了,也是涉及了很多,我们行业的算法,不是leetcode 中的算法,对编程水平的提升,的确有很大的帮助,脑子里有东西在写代码的时候
 乍一看很多,其实很少,计算机语言,本来就是实现设计的工具,或进行计算的工具,真正复杂的地方,涉及到各种协议的算法,硬件也好,
软件也好,,大家都一样,那你做芯片的话,那你就真的很强,但是做linux 嵌入式还是看 linux 内核的熟悉程度

环境布置

  • 建议在ubuntu 搭建环境
sudo apt install rustc # 一键补全rust 环境
#安装rustup
curl https://sh.rustup.rs -sSf | sh

测试 “hello world”

  • 安装完成以后 就会使用 cargo 命令
  • cargo 是一个工程管理工具
  • cargo new hello 创建一个hello的工程
  • 进入 src 文件夹
fn main(){println!("hello world\n");
}
  • 编译命令
cargo run #就可以开始编译

Rust 语法讲解,官网有详细的文档

我用的是国内翻译好的书上的截图,官方文档是英文的,就这点区别,其他完全一样

vscode的 环境配置

Rust 插件

插件设置

选择 rls 完全够用

剩下的就是 ctrl+shift+p 选择 编译任务 和 ctrl+shift+b 开始 build

Rust 常见问题

1. failed to select a version for the requirement

rust 如果是这种问题,rust 本身也会提供解决问题

2. Blocking waiting for file lock on package cache

  • 直接删除 %USERPROFILE%/.cargo/.package_cache
  • 然后修改 %USERPROFILE%/.cargo/config 文件更换为国内源就看以解决这个问题

查看关于rust 工程依赖库的文档,很方便

cargo doc --open

关键语法 所有权 和 枚举 的使用

这个枚举有点骚

所有权的问题,是Rust 编程的核心,C 的核心是 指针 C++ 是模板

不同于C++ 地方

小点

这个分隔符号还是一个挺好的

函数和Python 有点像

变量

  • let a; 这个 a 自身有块空间
  • a = 3; 直接在 a 上赋值是错误的
  • let b = a; 这种是可以的,为什么可以测试下
  • 如果想直接赋值就要使用, mut 进行声明
  • 是这个意思 let mut a = 3; a = 5; 这种就没问题

Rust 闭包 和 python 的很像

let f = |x| x + 1;

下面是PYTHON的 lambda

lambda arg1, arg2: arg1 + arg2  # arg1, arg2可以传入默认值

下面是C++的lambda 的表达式的方法

class A
{public:int i_ = 0;void func(int x, int y){auto x1 = []{ return i_; };                    // error,没有捕获外部变量auto x2 = [=]{ return i_ + x + y; };           // OK,捕获所有外部变量auto x3 = [&]{ return i_ + x + y; };           // OK,捕获所有外部变量auto x4 = [this]{ return i_; };                // OK,捕获this指针auto x5 = [this]{ return i_ + x + y; };        // error,没有捕获x、yauto x6 = [this, x, y]{ return i_ + x + y; };  // OK,捕获this指针、x、yauto x7 = [this]{ return i_++; };              // OK,捕获this指针,并修改成员的值}
};

总结下,就是越来越懒人们

条件判断 和 python 有点像

if a > b{print!("hello world\n");
}
if c > d:print("hello world")

干脆 大括号也去了得了

for 循环的使用和python3 有点像

let array = [1,2,3,4,5];
for ele in array.iter() {print!("ele {}",ele);
}
a = [1,2,3,4,5]
for t in a:print(t)

官方说这样的好处在于,不会有访问越界的问题发生

Rust 中的堆栈 和 垃圾回收机制 (GC) Rust 实际上是没有 垃圾回收功能的

截图为敬


String 是根据字符串的大小在堆上开辟一小块内存

  • 毕竟最终都是转化为机器指令的,堆栈是避免不了的
  • rust 中虽然没有垃圾回收机制的,都是默认的释放堆上的资源
  • 官方手册上的原话是:
  • 内存会自动地在拥有它的变量离开作用域后进行释放
  • 看到人家rust 手册。。。 。。。
  • 意思就是限制到了作用域中了

C++ 中的析构的模式称为 RAII(Ressource Acquistion Is Initialization)
书中称该设计思想为Rust 设计思想的核心

书中关于变量和数据的交互方式

  • 假如是一个简单的值或者字符(Rust 的 字符是4字节的 支持 unicode 编码,而C++ 和 C 都是 1字节的 utf-8 编码)
  • 进行入栈操作的赋值
let x = 5;
let y = x;
意思就是  5 是一个数值,绑定到x 上,  就是发生了入栈了
y = x; y 会 拷贝 x 中的数值,并绑定到自己的身上, 这就和我们平常接触到的语言就一样了
  • 上面的这些是Rust 为了高效的操作 使用了 trait 中的 copy

有一个基本的原则

  • 所有的整数类型,i64 i32 i16 i8 u64 u32 u16 u8
  • 所有的字符 char
  • 所有的浮点类型 f64 f32
  • 布尔类型 bool

在以上的规则中遵循 trait 的 copy 特性

  • 但是String的情况就是在堆上,前面的过程不变,但是为了回收堆上的内存,作了新的决策
    以下图为书中的原图,画的很清楚



图4-2

这个过程是必须要清楚的, Rust 中只是浅拷贝
这只是刚刚开始

Rust 的所有权规则

  • Rust 中的每一个值都有一个对应的变量作为它的所有者 (每个变量的空间就是相对隔离的,其他语言也这样,但是Rust 执行的更加彻底)
  • 在同一时间内,值有且仅有一个所有者 (“=” 会发生拷贝)
  • 当所有者离开自己的作用域时,他持有的值就会被释放掉(记住前面绑定的概念)

Rust 默认的操作 都是高效的 ,默认即是灵魂

let s1 = String::from("Hello World");
let s2 = s1.clone() ; //这个是操作是深度拷贝的操作

  • 深度拷贝,各自的指针指向各自的空间

Rust 中的元组 和 python 中的 元组 有点类似

let x:(u8,f32,i64) = ('a',3.1415926,-10000);

  • 访问的形式有点怪, 数组的访问形式还是挺好的
  • python3 中的元组结构

所有权和函数

将值传递给函数
进行赋值
将变量传递给函数触发移动或复制

看到了吧, 这就是Rust 的好处, 被移到了函数中,在函数中调用完以后其他地方就无法在使用了

  • 这种返回方式 我都忍不住看看是不是 return 了, 人家就是没有return

返回值与作用域有一个基本原则

  • 将一个值赋值给另一个变量时就会转移所有权,当一个持有堆数据的变量离开作用域时,它的数据就会被drop清理回收,除非又将所有权转到另一个变量上

Rust 的数组初始化 和数组的优化, 且不支持 自增和自减运算符

// 最正常的数组 python的 list 就长这个模样
let a = [1,2,3,4,5];
let b = [3;5]; //初始化 实际上是这个样子 [3,3,3,3,3]
let b: [i32;5] = [1,2,3,4,5]; //数组使用时必须进行初始化 否则 会报错,这点就比较好

  • 红色波浪线就粗误,就是因为没有进行初始化,黄色波浪线就是告警, 访问和数组的访问是一样的

引用与借用

  • 引用的概念和C++ 的引用差不多 (void * const ), 其实指针的存在,有很多的问题, 但是可以解决的问题大于存在的问题

  • look 这就可以 就继续使用 str_v1 了
  • 之前如果要返回必须要在函数中 返回才能用
  • 引用的存在是为了不发生移动,转换所有权
书中的示例代码

  • 返回的是参数的所有权,这个所有权就发生了转移,转移到了新的参数上

  • 就是说引用没有转移使用权


  • 借用
  • 但是可变引用就可以解决这个问题

就可以修改了

注意事项

悬垂引用

这就相当nice, C++ C 弱爆了,Rust 不给你犯低级错误的机会

引用规则

切片的概念

  • 一般性代码
  • 这里面有迭代器,中由引用来借用元素
  • 哇,return 活久见 只用于提前返回使用
  • 上面代码只是为了对比说明 数组切片的意义

字符串切片

剩下的就是重复出错,查看错误现象了

  • 切片存在的意义, 还是为了程序员不犯低级错误
  • python 中的切片, 是为了方便截取字符筛选的, 妈的,这是德国制造吧

所有权的重要性

  • 我理解的是内存空间的所有权,代表谁有权访问这块内存,谁有权修改,一旦离开作用域,在不采取引用的情况下,就会失效
  • mut 是为了告诉可以不可以修改数据
  • 总之就是严谨,规避了低级错误引发的大地震

Rust 中的 struct 使用

  • C 和 C++ 都得 在声明 结构体时都得需要 struct name{ int a}; 加分号
  • Rust 就不需要使用 结构体中的 分号
  • 必须先获取结构体的实例才行,才能正常使用
  • 结构体符合之前所有的规则

******************************************************** [20%] 分割线

函数中使用 struct

fn build_user(email: String,uername: String)-> User{ //并返回一个结构User{email: email,username: username,active:true,sign_in_count: 1,}
}
  • 可以简化的方法
  • 其他非著名使用方法

  • 可以进少代码量,有点像C++ 的继承的方法, 但是Rust 不是面向对象的


  • 元组式的 struct 访问

Rust 中通过派生 trait 增加使用的功能

  • 这self 更像是 C++ 中的 this指针 和 python 对象中的 self 有异曲同工之妙
  • 这其中还不包括 继承和特性的使用,
  • 我会把 trait 归到这部分,现在先跳过

Rust 枚举的使用

  • 是为了枚举使用的检测,检测枚举的情况,可以看到枚举的调用信息
  • 这是以往C/C++ 都无法达到的

Option 枚举的使用 是为了解决 空值的带来的坏的影响

  • match 是为了 匹配不同的枚举类型

_ 在match 匹配所有剩下的值 ,_ 在match 中是通配符号

  • 在Rust 中 枚举必须穷举所有的枚举类型 (这是特别需要注意的点)

  • if let 减少代码量的匹配方法

let if_let = Some(0u32); //还可以进行数值的检测if let Some(3u8) = if_let {print!("good \n");}else{print!("Not good\n");}
  • Option<T> 数据类型检测的优势就体现出来了
  • 使用Option 时也需要注意数据类型必须一致的问题

Rust 中的 mod 使用,有点像 Class 那样组织数据

  • pub 可以指定在mod 中 那些时公共拥有的


  • use 关键字 和 as 关键字 C++ && python3 的用法
  • 这样就可以在不同的作用域中进行使用

  • 这样的引入方法就相当的nice 了
  • 当然和python 中 一样 也支持相应的通配符号
struct 中 可以使用 new 来创建一个实例,有点像C++ 中的构造函数

接着, 我们 为 Guess 实现 了 一个 关联 函数 new, 用于 创建 新的 Guess 实例 ❷。 根据 这个 new 函数 的 定义

  • trait 共有特性的使用问题,可以共所有的类型使用
  • 这种特性,可以在内部,定义成不同的函数进行使用


trait 作为参数 和 语法糖的 使用 方式

需要使用代码进行熟悉 trait 的特性,String,str,vec!,hash_map 常用的和 泛型方法(周六日搞一搞)

******************************************************** [40%] 分割线

trait 特性

 #[derive(Debug)]pub struct point<T,Q>{      //这样还是属于自动推导的类型,进行使用,比C++ 的模板方式要更加高效//不至于编译两次,用哪一个生成哪一个,和 Some 的用法是完全一致的pub mm: T,pub mn: Q}let mut test_point = point{ //主动告诉编译器的不同的类型选项mm: 5i32,mn: 23u32};print!("test point {:?}\n",test_point);//trait 用来定义为共享的行为,trait 是在生成库的 时候为大家定义的 行为//更类似于公共共享的接口pub trait Summary { fn summarize(& self) -> String; }pub struct NewsArticle { pub headline: String, pub location: String, pub author: String, pub content: String, }impl Summary for NewsArticle { fn summarize(& self) -> String { format!("{}, by {} ({})", self. headline, self. author, self. location) } }pub trait  llp {fn llpf(&self) -> String; //这种用法是为了导入相应的结构体中,就是说这种用法没有}// 其中 trait 可以作为 一种 参数使用// 是一种 trait 约束的语法糖 的示例// pub fn llob<T:llp>(item: T) 实际上就是这种方式的语法,但是实现了一种语法糖的表现方式// pub 关键字也只是让私有变为共有,没有什么特殊的含义,oh yeach,最简单的权限实列pub fn llob(item: impl llp){ // 这是一个简单的实现 trait 的特性功能,而且可以作为参数使用item.llpf();}pub trait lloc {fn pppy(&self) -> String;}pub fn llod(ita: impl lloc + llp){print!("{} : {}\n",ita.llpf(),ita.pppy()); //可以同时使用两种不同的公共特性接口,}let test_circle= |x:u32| -> u32 { //这是rust 的闭包,闭包也可以作为一个参数使用x+1  };let gess = test_circle(10);print!("gess {}\n",gess); //还可以使用where 语法来解释,使用的trait 特性,减少代码的书写量fn some_debug<T,Q>(ita: T,itb: Q)->i32where T:lloc,Q:llp{32       }

这种方式,是为了使用trait 接口,对每个结构体都可以是使用这个公共接口,和C++ 的抽象接口,很像,也是形式上很想,意义和原理都不相同

这些是为了简化代码量
适配不同的情况,有适配器的思想和抽象接口的思想在里面

 fn returns_summarizable() -> impl Summary{NewsArticle{ // 之前为结构体生已经绑定了一个方法,使用 Summary 的特性,对结构体返回,其实是对trait的返回headline: "Oh head".to_string(), //NewArticle 本来就是一个结构体location: "Now".to_string(),author: "en".to_string(),content: "no".to_string()}}let let_test = returns_summarizable();print!("let guess {}\n",let_test.summarize());
  • 面向对象编程是为了多态
  • 模块化编程也可以实现
  • Rust 也是模块化编程,但是可以实现面向编程的功能,C 的话需要借助lds 连接器脚本 实现

  • new,为自己分配,在Rust 的智能指针出,会有解释 因为整数中实现了 display 的方法,所以包含了tostring 的特性
  • 可以将证书转化为 String 的字符串, String 集成了很多的方法
  • 上面的意思是 当且仅当 Display 和 PartialOrd 中的 cmp 和 display 都实现了之后,才会实现 cmp_display( cmp && dispaly)
  • 也就是说间接的实现了流程上的判断, 符合什么样的条件触发,cmp_display 的实现
  • 这中方法,在代码达到一定的程度时,他的优越性就显现出来了

  • 引用都会有生命周期, 一般情况下都是默认的,随着编译器的优化,对生命周期的标注会越来越少

标注生命周期是为了编译器计算变量的生命周期(了解就好)

  • 终于看到了 static, 说的太多没用,就是为了 在全局使用, 和 C/C++ python 的globa 一个意思,

这个就和前面的 普通变量的赋值 扯上了关系

这个语言真他娘的刺激


当个人 不好吗? 简单点不好吗, 有必要,搞的比C++ 还复杂吗

Rust 的自动话测试

运行cargo test ,就会对代码模块进行测试看看有没有问题, 其他的,这个知道就行了

闭包的类型

******************************************************** [50%] 分割线

Rust 的 闭包 和 trait 也是重点

剩下的50% 学习点

  • Rust 的高级特性 和 智能指针,就得慢慢来了,还包括安全用法和不安全用法的区别
  • Rust 的 STL 库 的使用
  • Web 服务器的实验项目 >> 这个是熟悉语言的最好方式
  • 有哔哩哔哩的视频,我得去看一下,有助于理解
  • Rust 中宏的定义和使用

需要声明引用的生命周期的案例

fn test_alive<'a>(x:&'a i32,y: &'a i32) -> &'a i32{ // 这里存在生命周期的不确定性,所以得显著的表明出来//这个周期的声明肯定是由 test_alive 这个函数开始的,以这个函数未结束//所以这个生命周期的生命也可以理解if x > y {x}else{y}
}

Rust & 就是指针

let ptr = &5; //活久见,直接指向了全局区的值,你他娘的,我大C的棺材盖压不住了
let ptr_test:&'static i32 = &7; //这是不是很刺激,其实是一样的道理,只不过省略了

trait trait 闭包 和 trait约束的
trait 的使用

pub trait Human{ //声明一个共有的特性,这个待定,定义公共的特性在里面
//也就是常见的C++ 抽象接口,但是意义不同
//C++ 可以通过抽象基类调用其子类,形成了抽象接口fn eat(&self) -> String;
}pub struct Woman{pub name:String,pub age:u32
}impl Human for Woman  {fn eat(&self)->String{format!("{} eat apple\n",self.name)}
}fn main() {let lili = Woman{name:String::from("Lidali"),age:22,};print!("{}",lili.eat());
}

struct 的使用

pub trait Human{ //声明一个共有的特性,这个待定,定义公共的特性在里面fn eat(&self) -> String;
}pub struct Woman{pub name:String,pub age:u32,pub sleep_time:u32,
}impl Human for Woman  {fn eat(&self)->String{ //共有特性format!("{} eat apple\n",self.name) }
}impl Woman{ //为我们增加单独的函数使用情况pub fn sleep(&self)-> bool{if self.sleep_time > 8{true}else{false}}
}fn test_trait(it: impl Human){ //trait 作为参数使用,怎么样就是抽象接口,实时证明trait 就是被用作抽象接口print!("human eat {}\n",it.eat());
}fn main() {let lili = Woman{name:String::from("Lidali"),age:22,sleep_time:9};print!("{}",lili.eat());print!("lili sleep st: {}\n",lili.sleep());test_trait(lili); //运行之后看打印,就知道怎么回事儿了
}

实时证明trait 就是被用作抽象接口, 之前的我理解错了, 在抽象接口的基础上理解,约束的问题,就容易了

trait 就是为抽象接口设计出来的

trait 就是为抽象接口设计出来的

trait 就是为抽象接口设计出来的

pub trait Human{ //声明一个共有的特性,这个待定,定义公共的特性在里面fn eat(&self) -> String;
}pub struct Woman{pub name:String,pub age:u32,pub sleep_time:u32,
}impl Human for Woman  {fn eat(&self)->String{ //共有特性format!("{} eat apple\n",self.name) }
}impl Woman{ //为我们增加单独的函数使用情况pub fn sleep(&self)-> bool{if self.sleep_time > 8{true}else{false}}
}fn test_trait(it:& impl Human){ //trait 作为参数使用,怎么样就是抽象接口print!("human eat {}\n",it.eat());
}fn opt_trait(x: Woman) -> impl Human{ //返回对应的数据结构的特性方法x
}fn main() {let lili = Woman{name:String::from("Lidali"),age:22,sleep_time:9};print!("{}",lili.eat());print!("lili sleep st: {}\n",lili.sleep());test_trait(&lili); //所有权的问题得注意let trait_ues = opt_trait(lili);print!("trait opt {} \n",trait_ues.eat());
}

还是之前的代码,但是返回了,业务中,可以广泛的应用

有条件的实现 trait 约束


pub trait one_pub{fn echo(&self) -> String;
}pub trait two_pub{fn print(&self) -> String;
}struct trait_debug{name:String,
}impl one_pub for trait_debug{fn echo(&self) -> String{"one_pub".to_string()}
}impl two_pub for trait_debug{fn print(&self) -> String{"two_pub".to_string()}
}struct sercert<T>{doit:T,
}impl<T> sercert<T> {fn new(doit:T) -> Self {Self{doit}}
}impl<T:one_pub+two_pub> sercert<T>{fn todosomething(&self){print!("yeah I am here\n");       }
}fn main(){let pre = trait_debug{name:String::from("PRE"),};let one = sercert::new(pre);one.todosomething();
}
  • 什么叫做有条件
  • one: 同时有pub_one 和 pub_two 这两个特性的类型才行
  • two: 如果没有,不好意思会直接报错,这就叫做有条件的 通过特性推导类型
  • three: 例子少,但是还是能够说明这个问题
  • 所以通过了特性,将数据类型 锁定到了一个范围之内,从而形成了约束, so, 书中给的例子,有说服力
  • 应为 Display 是所有的 基础数据类型的 特性,u32 i32 i8 u8 。。。
  • Partiaload 是所有比较大小的数据类型 u32 i32 i8 u8 。。。
  • 拿着些就特别有说服力

这就是trait 的约束

再次理解生命周期

struct alive_str<'a>{part:&'a str,
}fn main(){let kacha = String::from("baidu.com");let first_kacha = kacha.split('.').next().expect("Error");let index = alive_str{part:first_kacha};print!("kacha first {}\n",index.part);
}

如果在结构体中 有引用,那么就得显示的说明,声明周期,为什么呢,因为你不知道,到底谁先挂掉,所以要告诉编译器,part 的生命周期和alive_str 一样,但是,只是标注出来,显示告诉编译器,但是无法改变生命周期

还有就是只有引用存在标注生命周期的需求

编译器 目前 使用 了 3 种 规则 来 计算 引用 的 生命 周期 (书中原话)

  • 每一个 引用 参数 都会 拥有 自己的 生命 周期 参数。 换句话说, 单 参数 函数 拥有 一个 生命 周期 参数: fn foo<’ a>( x: &‘a i32); 双 参数 函数 拥有 两个 不同 的 生命 周期 参数: fn foo<’ a, 'b>( x: &'a i32, y: &'b i32); 以此类推
  • 当 只 存在 一个 输入 生命 周期 参数 时, 这个 生命 周期 会被 赋予 给 所有 输出 生命 周期 参数, 例如 fn foo<’ a>( x: &'a i32) -> &'a i32。
  • 当 拥有 多个 输入 生命 周期 参数, 而 其中 一个 是& self 或& mut self 时, self 的 生命 周期 会被 赋予 给 所有 的 输出 生命 周期 参数。 这条 规则 使 方法 更加 易于 阅读 和 编写, 因为 它 省略 了 一些 不必 要的符号

如果符合这三条就不需要显示的标注生命周期, 默认情况下符合以上,就不需要,标注,如果no,就需要标注,好的结束,nice



到这里就可以完全弄懂 trait 和 生命周期 的意图了

闭包和迭代器

struct CloseCircle<T>
where T:Fn(u32)->u32                                    //闭包的特性约束 FnMut(u32)->u32 FnOnce(u32)->u32 消耗捕获的变量
{func:T
}fn main(){let test = |num|{print!("num is {}\n",num);                      //这是默认返回的特性num + 10};let o = test(1);print!("o {}\n",o);let cankao = |x| x+10;                              //最简闭包最为使用的功能,显示的使用一个闭包并进行返回,也就是可以当作参数使用let cankao_v1 = cankao(10);print!("cankao_v1 {}\n",cankao_v1);let y = 100;let cankao_v2 = |x| x == y;                         //只能在闭包中使用捕获上下文的功能print!("cankao_v2: {}\n",cankao_v2(100));let close_circle = CloseCircle{func:|x:u32| -> u32 {x+120},};print!("close_circle test {}\n",(close_circle.func)(130));let v1 = vec![1,2,3,4];let mut iter = v1.iter();iter.next(); iter.next(); iter.next(); iter.next();print!("iter {:?}\n",iter);
}
获取枚举变量中的值
let test_enum = Some(&5);
print!("test enum {}\n",test_enum.unwrap());
  • 由此可知这是由 枚举的 共有trait 获取 枚举中的值, 这个理念不错,我喜欢
  • Rust 的编译器 有点烦 还管怎么 命名的,要不然 还告警 … …
  • unwrap() 这个 trait 方法 记住意思very 重要,在以后的编程里面,就是相当nice的玩意

迭代器的消耗问题

let v1 = vec![1,2,3,4];let mut iter = v1.iter();iter.next();iter.next();iter.next();iter.next();print!("iter {:?}\n",iter);print!("v1 {} 的数组访问 {} \n",0,v1[1]); for it in iter{//所谓的消耗了迭代器,就是 指针的位置移动到了终点//按照C++,python 的情况下的理解就是这个样子,所以,书中的这个消耗//你是说得对,但是,不能这么玩呀print!("证明是否消耗了迭代器: {}\n",it);}

所谓的消耗了迭代器,就是 指针的位置移动到了终点

现在想一想这个特性的约束还是 十分的巧妙在里面

生成新的迭代器的方法

 let v1 = vec![1,2,3,4];let mut iter = v1.iter();iter.next(); iter.next(); iter.next(); iter.next();print!("iter {:?}\n",iter);print!("v1 {} 的数组访问 {} \n",0,v1[1]); for it in iter{//所谓的消耗了迭代器,就是 指针的位置移动到了终点//按照C++,python 的情况下的理解就是这个样子,所以,书中的这个消耗//你是说得对,但是,不能这么玩呀print!("证明是否消耗了迭代器: {}\n",it);}let test_opt = Some(&5);print!("Test Opt {}\n",test_opt.unwrap());//迭代器是有惰性的,除非使用,否则没有任何的变化let v1_it:Vec<_> = v1.iter().map(|x| 2*x).collect(); //只会在迭代器移动是使用数值生成一个新的迭代器,但是不会对原有数据修改for t in v1{print!("update vec t {}\n",t);}

迭代器存在惰性

就需要使用,关键是collect 特性,促使迭代器动起来, 和 python 的 yield 的 关键字有异曲同工之妙

  • iter 中的 filter 的特性 可以更具闭包 选择某些数据,然后在使用 collect 收集器起来,进行返回很实用
  • 迭代器中返回的是Option Some(T),所以涉及到了enum 的解包问题
  • 现在想想闭包和 trait ,这俩好棒呀,还有Option 这个枚举真的不错
  • 道理上来讲,迭代器要比 loop while for 这些循环 要高效一些

自定义创建一个迭代器

#[derive(Debug)]
struct ItWonderful{cnt: u32,
}impl Iterator for ItWonderful{                          //使用迭代器的特性type Item = u32;fn next(&mut self) -> Option<Self::Item>{self.cnt += 1;if self.cnt < 6 {Some(self.cnt)}else{None}}
}
// 对于一般的u32 i32 u64 i64 都有 copy 的特性fn main(){  let mut dabu = ItWonderful{cnt: 0,};for _it in 0..5{dabu.next(); // dabu 会发生变化,}print!("dabu {:?}\n",dabu);
}

这个next 方法就是相应的迭代器

还得养成一个new的习惯

struct ItWonderful{cnt: u32,
}impl ItWonderful {fn new() -> ItWonderful {ItWonderful{cnt:0}}
}

就是为了减少代码量

要记住字串符没有 Copy 的 特性,得clone 进行使用

再看 Copy 特性的问题

let  _str = "hello";          //栈中的数据区域,无需回收 实际类型为 str 字符串切片
let _str_c = _str;                 //_str_c 获取到了_str 的所有权 "hello的" 其实是字符数组的 Copy 功能//常规赋值发生拷贝
print!("_str {}\n",_str);let _str = String::from("hello"); //在堆上开辟的字符串,在堆上的话就只有 浅拷贝 ,没有 Copy 特性
let _str_c = _str; // ---- once
let _str_d = _str; // FIXME: 是无法访问的

Box 智能指针的使用场景 (书中原话)

• 当你 拥有 一个 无法 在 编译 时 确定 大小 的 类型, 但又 想要 在 一个 要求 固定 尺寸 的 上下文 环境 中 使用 这个 类型 的 值 时。
• 当你 需要 传递 大量 数据 的 所有权, 但又 不 希望 产生 大量 数据 的 复制 行为 时。
• 当你 希望 拥有 一个 实现 了 指定 trait 的 类型 值, 但又 不关心 具体 的 类型 时

Deref trait 定义 引用的含义,自定义指针,快乐 ~^^~

use std::ops::Deref;struct auto_ptr<T>(T);//实现一个智能指针的方法 new
impl<T> auto_ptr<T> { fn new(x:T) -> auto_ptr<T> {auto_ptr(x)}
}//为自定义的智能指针添加
//解引用的方法
impl<T> Deref for auto_ptr<T>{  type Target = T;fn deref(&self) -> &T{&self.0}
}// 这是一个字符串切片的表面量
fn main(){  let int_ptr = auto_ptr::new(0u32);print!("init_ptr {}\n",*int_ptr);
}

书中关于: type Target = T 的解释

type Target = T; 语法 ❶ 定义 了 Deref trait 的 一个 关联 类型。 关联 类型 是一 种 稍微 有些 不同 的 泛 型 参数 定义 方式

慢慢来以后解释

Rust 函数默认 引用解引用的 隐式转换

Rust 会在 类型 与 trait 满足 下面 3 种 情形 时 执行 解 引用 转换:
• 当 T: Deref< Target= U> 时, 允许& T 转换 为& U。
• 当 T: DerefMut< Target= U> 时, 允许& mut T 转换 为& mut U。
• 当 T: Deref< Target= U> 时, 允许& mut T 转换 为& U。

******************************************************** [60%] 分割线

Rust 强大的告警功能

其实没错误只是,不符合他的命名规则

JetBrains 27 寸战神 名不虚传


补全效果比智能检测比 Vscode 好的多


Rust 元组和数组 的区别

  • 元组不支持迭代,可以自己实现,官方也不建议创建迭代,因为 tuple 支持不同的数据类型,但是满足迭代器的条件,就是每次返回一个相同的 数据类型的,就算是使用Option<T> 这个T 的类型是唯一的,所以无法完成迭代
  • 官方如果要使用迭代的话, 建议使用数组,可以在元组中使用多个数组,在对数组迭代,访问

元组和 数组的小用法

    let test = (1, 2, 3, 4); //元组的的使用方法let (first, second, third, fourth) = test; //常见的元组解包使用let test = [1, 2, 3, 4];let [first, second, third, fourth] = test; //常见的数组解包let test = [1, 2, 3, 4, 5];let mut it = test.iter(); // 迭代器必须是变化的,换句话说是必须是移动的let it = it.next();print!("Some<T> {:?}\n", it);for it in test.iter() {// 使用 for 迭代 对 Option<T> Some(T) 解包print!("it {}\n", it);}

元组和数组的结合访问

fn print_array<'a, T>(x: &'a [T; 5], y: &'a str)
whereT: std::fmt::Display, //对参数追加trait 约束,为了正常使用{} ,格式化输出
{print!("array {}: ", y);for it in x.iter() {print!("{} ", *it);}print!("\n");
}fn main() {let array_one: [i32; 5] = [1, 2, 3, 4, 5];print_array(&array_one, "one");let array_two: [i32; 5] = [7, 8, 9, 0xa, 0xb];print_array(&array_two, "two");let tuple_mux = (&array_one, &array_two);print_array(tuple_mux.0, "tuple first");print_array(tuple_mux.1, "tuple two");
}

Result
### Rust 打印小方法, 和 C中的打印有些相同

let test = 0x1234;
print!("0x{:04x}\n",test);

一下截图来自通过例子学Rust


这是在以当前的作用域为有效的声明,和遮蔽有关系,这个这个官方,解释的很官方,加一个mut 一样是可以修改的

  • 看下面所示的代码示例
fn main(){let mut _nums = 0x100;{let mut _nums = _nums;_nums = 0x200;print!("nums 0x{:03x}\n",_nums);}
}


Rust 中的显示转换

这就和 C 中的强制类型转换变的会一致

我感觉写出声明心里踏实点

as 关键字 可以作为 显示声明符合

这个和 typedef 相差不大 这个使用

From Into 特性 用作网络解包,可以整块解包,我还是喜欢C 的 ptr





主要是根据元组的顺序推导出来的

逐步可以解构访问的枚举方式

引用 解引用 解构

fn main() {let ref mut _ptr;let mut _value = 0x100;_ptr = &mut _value;print!("ptr dereference is 0x{:04x} \n", *_ptr);
}

这种声明就容易读

Rust 使用熟悉

#[allow(dead_code)]
enum Color<'a> {//双元的生命周期Red(&'a str, &'a i32),Black(&'a str, &'a i32),
}fn main() {#[allow(unused_imports)]use Color::{Black, Red};//对Color 进行初始化的示例使用let user_color = Red("red", &0x2);match user_color {Red("red", &0x2) => print!("yeach matched \n"),_ => print!("yeach nothing matched \n"),}
}

卫语句的使用也很使用

这种有利于 在枚举的时候 动态的获取数据类型

这种使用方法很普遍,尤其在逻辑越多的时候,越明显

// `age` 函数,返回一个 `u32` 值。
fn age() -> u32 {15
}fn main() {println!("Tell me type of person you are");// 这个绑定的语法相当好用match age() {n @ 1..=10 => println!("this switch is {}\n", n),n @ 11..=13 => println!("this switch is {}\n", n),n @ 14..=16 => println!("this switch is {}\n", n),_ => println!("default switch \n"),}
}

减少的逻辑代码很客观

循环标签的使用

fn main() {let mut cnt = 0;let pl = 'level_1: loop {cnt += 101;while cnt > 2 {if cnt == 100 {break 'level_1 cnt;}cnt -= 1;}};print!("pl value is {}\n", pl);
}

跳出第几层 的循环,不用在一层的一层的跳,咱们直接跳,这就很灵活了,实际开发中,经常会用到


官方中文学习手册
https://rustwiki.org/docs/

Move trait 的 特点

没有 move 的情况

编译器写的很清楚,无法获取 a 的 mutable attr

加上move 之后

move 的作用是将 强制 将 闭包 外的 所有权转移到 闭包内使用,否则默认的情况下,只能捕获借用,不能获取完整的所有权

和C++ 一样的析构函数,手动回收资源,用于自己创作的自定义类型

感冒头痛 … …

Some 解包小技巧

fn main() {let mut data = Some(0);let mut _use_data = || -> Option<i32> {//返回某些数值并使用? 解包,在Option 返回的闭包中data = Some(5);Some(data? + 10)};println!("data {} \n", data.unwrap());
}

年前最后一项技能树 Rust ,攻碉堡 ing (Bilibili 视频整理)相关推荐

  1. 【信息系统项目管理师】高项案例分析攻略

    [信息系统项目管理师]高项案例分析攻略 摘要 高项的案例分析,都说只要做对计算题都稳过,这个结论不假,但也要其他有其他两道文字案例题分数得支撑.尤其在通过卡案例来维持低通过率的时候,这结论并不完全适用 ...

  2. 【干货】2021短视频营销攻略:短视频内容策略下的5i沟通法则.pdf(附下载链接)...

    大家好,我是文文(微信号:sscbg2020),今天给大家分享阿里妈妈和淘宝短视频于2021年1月份联合发布的报告<2021短视频营销攻略:短视频内容策略下的5i沟通法则.pdf>,短视频 ...

  3. 视频号运营攻略大全,视频号从0到1运营变现教程丨国仁网络资讯

    众所周知,近年来国内短视频行业蓬勃发展,抖音日活6亿,快手日活也达5亿多,腾讯一直眼馋着这块蛋糕,不仅投资了快手,还自己开发了短视频APP--微视. 可微视的发展不如人意.而视频号作为微信的" ...

  4. rust最美建筑_[资料整理]动物之森的美丽物语 (多图;补完)

    Agent S 生日: July 2nd 性别: Female 口头禅: sidekick 个性: 活泼 种族: 花栗鼠 看图说话: "I'm gonna, like, save the w ...

  5. 微信视频号攻略:转发视频号的视频到自己的视频号上

    新手如何转发视频号的视频到自己的视频号上,需要创作还是直接发呢? 我相信你开通视频号,都想赚钱但是真的你知道怎么赚钱吗? 视频号背靠微信,而且拥有最多的用户现在微信官方一直投入大量资源使劲推,视频号重 ...

  6. 多项新规重磅发布,微信视频号近期需要关注这几点

    随着功能的完善和内容生态的丰富,视频号逐渐放慢产品更新频率,将重点放到商家准入标准.创作者扶持计划上来,本期我们将更侧重解读平台新规,帮助大家了解行业动向,把握最新趋势. 01 视频号小店结算规则修订 ...

  7. 直播攻略:网易视频云送上OBS直播完整版教程

    OBS是什么? OBS是一款直播串流软件,中文无广告,完全免费,含32位与64位版本,通吃各种电脑,支持MAC的OS X系统. 各大平台都有自己的直播软件了还需要用OBS么? 因为,当前平台直播软件存 ...

  8. 短视频营销攻略:短视频内容策略下的5i沟通法则(2021.1).PDF

    来源:阿里妈妈 公众号:参一江湖 以上是资料部分内容截图,更多海量精选内容 公众号:参一江湖 8月第一周资料总览(8.1-8.7) 2021年中国人工智能应用趋势报告. 2020-2021年中国短视频 ...

  9. 新增微信小程序和WebRTC连麦直播等多项能力,即构实时音视频SDK再升级!

    经过2018年小半年的闭关练功,即构ZEGO团队铸造了不少黑科技.本文将为你带来即构ZEGO实时语音视频SDK近半年新增能力和功能优化的最新进展. 更懂应用场景的语音视频云 作为全球领先的实时语音视频 ...

最新文章

  1. Java 面试知识点解析(七)——Web篇
  2. 轻量级HTTP服务器Nginx(Nginx日常维护)
  3. Angular 9.0.0 版本已发布!
  4. Android 虚线分割Shape
  5. bzoj3601 一个人的数论 (拉格朗日插值求系数)
  6. 邮件系统IP被CBL列黑,怎么样里面申诉呢?
  7. 【机器人学】机器人运动学基础
  8. app移动接口开发需要注意什么
  9. 2018年深圳杯论文_2018.5.21/建模日记/深圳杯
  10. could not get batchedbridge, make sure your bundle is packaged correctly
  11. 教你怎么用手机进入路由器管理界面
  12. 百度风云榜实时热点API
  13. 飞秋官方下载 找了很久的
  14. UNITY个人版设置深色主题
  15. Android微信支付集成流程及其常见错误
  16. Asynchronous FIFO with gray code(异步FIFO verilog设计理念)
  17. 笔记本高分辨软件兼容问题,字体太小或模糊
  18. 活动详情页面html代码,折扣活动详情.html
  19. python工控开发框架_GitHub - hzglitter/isf: ISF(Industrial Security Framework),基于Python的工控漏洞利用框架...
  20. 图像运算和图像增强一

热门文章

  1. 视频监控:特征识别真的优于人脸识别吗?
  2. Grunt安装中遇到的问题汇总
  3. vim设置solarized配色
  4. IT工作十年总结之3个图表与统计查询对象
  5. html5 Web Workers
  6. 计算两个字符串之间是否包含的简单方法
  7. 海天学院的打造IT人才讲座准备
  8. 形象!Google Earth增实时雨雪演示功能
  9. oracle test就死,简单说明Oracle数据库中对死锁的查询及解决方法
  10. python里面ca_Python SSL服务器提供中间CA证书