Move和Copy
let a = 10;
let b = vec![1, 2, 3];
{
let (x, y) = (a, b);
}
let c = a; // a是i32基本类型,在大括号里a会copy给x,产生新的副本。它仍然有所有权
let d = b; // b已经被move给y,所以这里不能使用b
- 没有实现Copy trait时,默认是Move。即所有权移动
- 基本类型以及由基本类型构成的复杂类型,编译器会自动实现Copy
- 实现Copy trait时,复制,传参与函数返回值时是按位拷贝,不会转移所有权
Drop的顺序
{
let s1 = "Hello world".to_string();
// 这里s1move到了vec中
let arr = vec![Box::new(s1)];
// 先drop vec,再drop box,最后drop s1
// 这里的先后是指调用先后,最后调用的被最先清理掉内存
}
生命周期短的先drop,生命周期长的后drop
Sized与DST
-
Sized: 编译期 - 可以放在栈上
- Rust 有
Sizedtrait 和?Sizedtrait bound - 所有的泛型结构默认
T: Sized
- Rust 有
-
DST: 运行期 - 一般只能放在堆上(stack_dst)
- trait object(生成VTable)
- [T] / str
- struct / tuple 包含 DST(如:
Mutex) - 对于 DST,指针是 "fat pointer"
-
问题:
- Q1:指向 slice 的指针在堆还是栈上?
- 指针本身在栈上,所指的实际数据一般在堆上
- Q2:很多数据结构,如 Mutex 包含 DST,为什么它能放在栈上?
- Q1:指向 slice 的指针在堆还是栈上?
常用基本的trait
- Debug/Default/Clone
- Send/Sync/Unpin(一般自动实现了)
- PartialEq/PartialOrd/Hash/Eq/Ord
- Serialize/Deserialize (use feature flag)
- Iterator
- Deref<Target> / AsRef / From<T> / Into<T>
Rust中的test
- unit test
- 单元测试,它可以访问到所在crate的所有数据结构和API。无论是pub还是internal
- doctest
- 执行文档注释中的测试代码,保证注释文档代码的正确性。和unit test使用同样的运行方式:cargo test
- integration test:见 tonic
- 它和平常的crate没有差别,只能调用所需要测试的crate的公开API
- fuzz:
honggfuzz-rs(见 snow) - proptest:
quickcheck或proptest(见:cellar) - benchmark:
[benchmark]现在还是 unstable,可以用criterion(见:cellar)- 主要是测试函数或者API的性能。通过短时间调用N次API来测量
Future: Leaf / Non-leaf事件
-
Leaf:一般是运行时定义的内部事件(e.g. event)/ 外部事件(e.g. io)
tokio::time::Sleeptokio::net::TcpStream
-
non-leaf:一般用 async 定义的 future
async move {}
let fut = async {
let mut stream = TcpStream::connect("localhost:8000").await?;
stream.write(b"hello world\n").await?;
}
程序中大部分是non-leaf事件,它大多时候依赖于Future在leaf事件上执行poll操作,从而让状态流转
Rust中的Pin trait
- 原来左边的b内存存储的是0x1002这个地址值,这个地址的内容是左边的a
- 经过swap交换之后,右边的b还是存储的0x1002这个地址值,但是这个地址里面的内容已经变成了原来右边a的内容
- 同理原来右边b的值,经过swap之后,现在指向了右边的a
- 这两个从而造成了一个环
网络协议栈
Rust对L3-L7都有不错的支持
中心化服务的一般设计
一般通过将该过程分为多个layer来分别处理
Rust对网络协议的支持
- tonic用于支持GRPC
- tracing用于日志和log,功能强大,API简单
介绍tonic:Rust 下 GRPC 服务
- tower-service
- 基于 prost,生成 ProstCodec
- 为你的 grpc service 定义生成
Servicetrait
pub trait Service<Request> {
type Response;
type Error;
type Future: Future<Output = Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>;
fn call(&mut self, req: Request) -> Self::Future;
}
Rust TLS 支持
- openssl
- rustls (基于 ring)
- tokio-tls-helper
Noise Protocol
-
TLS vs Noise protocol:动态协商 vs 静态协商
-
Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s:
- I:发起者的固定公钥未加密就直接发给应答者
- K:应答者的公钥发起者预先就知道
- psk2:把预设的密码(Pre-Shared-Key )放在第 2 个握手包之后
- ChaChaPoly:对称加密算法
- BLAKE2s:哈希算法
-
协议最少 0-RTT (x 或者 xpsk),之后就建立好加密通道,可以发送数据
接口
- build:根据协议变量和固定私钥,初始化 HandshakeState
- write(msg, buf): 根据当前的状态,撰写协议报文或者把用户传入的 buffer 加密
- read(buf, msg):根据当前的状态,读取用户传入的 buffer,处理握手状态机或者把用户传入的 buffer 解密
- into_transport_mode:将
HandshakeState转为TransportState - rekey:在传输模式下,用户可以调用 rekey 来更新密钥
宏编程
声明宏
macro_rules!使用它来声明#[macro_use]/#[macro_export]使用它来导入和使用
过程宏
- 类函数宏(function-like macros):
println!(...) - 派生宏(derive macros):
#[derive(Debug)] - 标记宏(attribute macros):
#[tokio::main]
资料
【程序君的 Rust 培训(2)-哔哩哔哩】 b23.tv/2lwrfGP