rust
2019-04-02 09:43:36 41 举报
AI智能生成
为你推荐
查看更多
rust
作者其他创作
大纲/内容
枚举和模式匹配
枚举
相对于结构体的
如果通过结构体来模拟枚举但定义方法时就需要多处定义了
opinion
空置控制手段
rust中没有空置的概念
本身是常规enum 但是由于常用 对其作了优化
match
match和if let 的关系
if let 就像是只有一个分支的match
在简单match中可以考虑有限用if let
必须时穷尽的
包、crates和模块
包
cargo的一个功能
crate基于包构建
一个包中可以带有一个或者零个crate和任意多个crate二进制文件
一个包中至少有一个crate
默认的crate
如果有src/main.rs
src/main.rs就是crate根
此时默认有一个和包同名的二进制crate
若果有src/lib.rs
此时默认存在一个和包同名的库crate
src/lib.rs是crate根
src下同时有main.rs和lib.rs
有两个和包同名的crate
如果包需要有多个二进制crate时
可以把文件放到src/bin下
这个路径下的每个文件都是一个独立的二进制crate
crates
是一个模块的树形结构
库和二进制项目的存在形式
模块
和use与私有性相关
mod name;
将模块的声明和定义分割
路劲
命名例如结构体、函数或者模块的方式
私有性边界
所有项(函数、方法、结构体、枚举、模块和常量)默认是私有的。可以使用 pub 关键字使项变为公有。不允许使用定义于当前模块的子模块中的私有代码。允许使用任何定义于父模块或当前模块中的代码。
补充
来源
rust编程之道
extern
用来导入第三方包
如果是2018版本的rust
这个字段可以不用考虑了
重要的第三方包
lazy_static
说明
惰性静态初始化
使用场景
需要全局变量(static)
但是这种变量类型无法用静态变量或者普通常量
比如hashmap,或者是更加复杂的变量
这种变量有一个共性
需要动态分配内存
固定的格式
lazy_static! {// 使用宏来定义变量[pub] static ref name1:type1 = value1;[pub] static ref name2:type2 = value2;//etc}
通用集合类型
各种容器
获取元素推荐使用get 不会轻易panic
测试
#[test]
单元测试
cargo test
tests文件夹
该文件夹下的每个文件都会编成一个crate
用于集成测试
实际中可以用别的测试框架来替代
泛型、特质和生命周期
泛型
常见使用场景
泛型函数
泛型结构体
泛型方法
注意
impl 后必须加上
泛型enum
性能
单态化
编译时会把所有泛型出现的地方都生成一个具体类型的实例
由此可见 泛型使用会出现可预期的编译文件体量增大
但是 这么做 本身除了影响大小外 对执行性能并没有过多的影响
特质(trait)
定义共享的行为
类似于接口
关于trait的实现
和接口类似
注意孤儿规则
默认实现
在定义trait时,直接将方法实现了
已经被trait实现的方法会被默认实现
意义
可以调用trait中其他的方法
在对类型实现trait 无需再次实现
泛型约束
三种写法
fn some_fn(t:T){}
fn some_fn(t:impl trait1+trait2){}
trait作为返回值
写法
impl trait1
返回一个已经实现了对应trait的未知类型的实例
和if match类似
返回的必须是用一个未知类型
生命周期和引用有效期
rust中的每一个引用都有生命周期
对象
引用
函数签名中生命周期
格式
fn name(x:&'a str)-&'a{}
特点
这种函数至少有一个入参
这种函数的出参肯定时一个引用
当从函数返回一个引用,返回值的生命周期参数需要与一个参数的生命周期参数相匹配
个人理解
x的声明周期注解其实是指传参时的x的生命周期如果不加上生命周期注解,会导致回传的引用是个无效(已经被销毁)的引用
结构体的生命周期
函数式编程
闭包
与一般函数的不同之处
不强制要求对出入参进行类型注明
闭包定义会为每个参数推断一个类型
对于同一个闭包变量来说
推断类型只会执行一次
当尝试传入和第一次参数类型的不同的变量时
会报类型错误
简单格式
|a|a
关于闭包唯一调用的思路
场景
当使用一个变量存储闭包时,每次需要闭包内部逻辑时,都得调用一编,需要对这种情况进行优化
思路
使用结构体包装
涉及
结构体
trait绑定
闭包其实是一种实现了Fn/FnMut/FnOnce的一种类型
这个结构中一个字段存闭包,一个存储闭包的计算值
为结构实现一个对计算值赋值的方法(可以通过 match+some/none实现)
存在的局限性
只会返回相同的值
可以用hashmap来保存多个值
可以直接变量遮蔽来返回不同的值
对类型的限制也比较大
可以用泛型来优化
捕获环境
方式
获取所有权
实现了FnOnece
可变借用
实现了FnMut
不可变借用
实现了Fn
根据环境类型来判断使用哪种方式捕获变量
强制获取捕获变量的所有权
move
迭代器
获取迭代器
底层时实现了一个Iterator的trait
这个trait中只有一个next方法
特殊
into_iter()
iter_mut()
可写
iter()
消费迭代器
每次取元素都会消费迭代器
sum可以一次性全部消耗掉迭代器
sum会获取当前迭代器的所有权
迭代器的方法比for循环更加高效
但是可读性降低
智能指针
rust中的指针
& 引用(借用)
BOX
堆上分配内存
Rc
引用计数
所指的内存可以存在多个所有者
但所有者为0时,清理内存
String
Vac
特性
一般由结构体实现
实现了Deref和Drop的trait
Deref
语序智能指针表现的象引用
Drop
回收
引用和智能指针的区别
引用只是引用
智能指针拥有
unsafe指针
Box
堆上放数据
栈上放指针
套娃结构体
递归类型
理论上是可以无限递归的
大小在编译期是不知道的
由于box类型大小时可知的,嵌入box就可以创建套娃了
典型
cons list
rust box 版
解引用
强制多态
使得box类型在匹配其他类型时更加方便了
内容
实例离开作用域时所需要执行的操作
注意点
实例离开作用域遵循先进后出
因此可以用drop作为一个类似于golang的defer的函数
限制
孤儿原则
只能用本地类型
drop在prelude中的
drop方法时不允许显式调用的
std::mem::drop
手动强制清空内存
本质
析构函数
对应构造函数存在
分支主题
引用计数智能指针
启用多所有权
引用为0时清理内存
注意 这玩意只能用于单线程
每次Rc::clone一次
计数就加一
每次离开作用域
会减掉作用域中的计数
strong_count
返回当前的计数
RefCell
内部可变性
允许改变不可变引用的值
代表数据唯一的所有权
rust
rust中文资源
rust教程文档索引(中文)
rust官网
rust文档
cargo
cargo.toml
dependencies
语义化版本
cargo.lock
除非caogo.toml中指定了crates的新版本,否则重复使用项目中已经存在的cartes版本
锁依赖的版本用
cargo update
将cargo.toml中声明的crates强行升级,绕过cargo.lock,升级成功后cargo.lock中的相关内容也会被更新
more
profile.*
opt-level
优化等级
0最低
发布到crates.io
文档
///
cargo doc --open 检查当前文档的html形式
支持markdown格式
文档内部代码是可以运行的
常用注释
panics
描述panic!
errors
描述错误
safety
使用了unsafe代码
特殊的
//!
描述库信息
对多层级的简化
pub use (重导出)
发布前要注册账号
将api token注册的本地
在包信息中可以加上license信息
publish
发布
yank
撤回
注意 代码crates.io上的代码并不会消失
敏感信息一定检查仔细
否则只能覆盖代码处理
工作空间
toml中的workspace
member数组
工作空间内的crates的依赖方式
和普通不一样
和从github上面获取依赖类似
安装二进制文件
install
安装地址
~/.cargo/bin
自定义命令
有空再研究
工程结构
src
源码存放位置
工程核心配置
自动生成的锁依赖的文件
target
默认的编译完成的文件的存放位置
.cargo
该目录下可以存放config 作为项目cargo配置
build.rs
添加build时的自定义操作
通用编程概念
标识符
规则和其他语言一样
原始标识符
情景
在调用其他语言的函数时,由于各语言的关键字不同,可能出现rust语言中的关键字和其他语言中的普通标识符重名的情况
方法
以r#作为前缀
变量与可变性
用途
防止出现bug
让coder自主选择性能和可读性
追求性能 使用可变变量
追求可读性 使用不可变变量
mut 可变
没有mut 不可变
let 和 const 的区别
const总是不可变的,let是可选择的
const的声明必须带上类型,let可以让语言自行推导
const可用的作用域更加广泛
变量遮蔽
需要改变变量类型,但是不希望重新用一个新变量名时;
数据类型
基础类型(标量类型)
整型
i 有符号,u没有符号
i/u后面接长度
i/u后面可以接size 表示无法确定整型的长度
注意溢出
默认i32
浮点型
f开头
f后接长度
默认u64
bool
字符类型
复合类型
元组
解构
由于let支持模式匹配
直接用let对元组进行结构
异构有限
数组
同构有限
访问元素
索引
越界
当数组的长度是一个常量时,越界会被检查出来
否则会抛出runtime错误
函数
关于let的一点说明
let这种赋值语句不会返回值,只有!(底类型)
关于语句执行的说明
碰到分号继续向下执行
碰到语句,执行语句
当一个块中分号后面没有语句 返回一个单元值:()
但一个块中不是以分号结尾的,则返回最后一个表达式
注释
// /**/
///用作文档 兼容markdown
控制流
if
保证分支的类型相同
loop
在跳出循环时 加上表达式 可以返回表达式的值
所有权
堆内存释放方式
rust在}后会调用的drop清理堆内存
但出现多个变量调用同一个堆内存地址时会出现问题(二次释放)
变量和数据交互的方式
移动
类似于 let y =x (x已经声明过)
栈变量不会移动
会拷贝生成两个相同的值存入栈中
x y都是有效变量
copy
堆变量会发生移动
不会拷贝原有值
会拷贝指针,同时删除x的指针不然会出现二次释放的情况
x已经成为了无效变量
移动和浅拷贝的区别
原来的变量被清理掉了
drop
克隆
阻止移动的发生
clone()
深入
底层和是否实现了Drop trait相关
drop和copy时互斥的
原生copy的
bool‘
浮点
字符
函数传参和赋值语句是一样的要注意移动或者复制的发生
将值赋给另一个变量时移动它。当持有堆中数据值的变量离开作用域时,其值将通过\u00A0drop 被清理掉,除非数据被移动为另一个变量所有。
引用(借用)
避免因为移动导致变量不可用,同时又不想用clone的情况下
引用而不拥有 &
避免了移动所产生的问题
但是由于没有所有权
也没有办法对原变量的值做出修改
在这种情况下就要使用可变引用 &mut
同一个作用域中的同一个变量只可以有一个可变引用
同时可变引用和不可变引用也是互斥的
这么做避免了数据竞争
悬垂引用
引用了一个已经被释放的地址
解决办法
不要用引用直接返回值
引用规则
在任意给定时间,要么 只能有一个可变引用,要么 只能有多个不可变引用。引用必须总是有效
slice
下标
a..b
a..=b
..b
..
全集
这个类型的变量会被move
一般都是使用&str(string的指针)来传递数据
构造函数的特殊写法
可以使用同名的变量,对构造语句进行简写
可以使用已有的结构体实例的部分字段给自己对应字段进行赋值
元组结构体
只有类型,没有字段名
想对一类元组进行具名
技巧
可以为结构加上#[derive(Debug)]
从而使得可以用{:?}/{:#?} 来打印结构体的字段
impl
首个参数为&self
用 . 来调用
关联函数
首个参数不是&self
用::来调用
多个impl块
分割功能
更多的是和trait搭配
0 条评论
回复 删除
下一页