0%

开发第一个纯rust应用

rust程序设计语言 介绍了关于rust的方方面面, 我跟着学了两遍,中间隔了差不多一年,每次都是从零开始入门, 最近两个月用rust实际开发了个应用,才算真的入门. 这里记录下使用中的一些体验.

1 关于rust本身

数据类型,流程控制都很基本,crate和包封装也是基础.

1.1 所有权

所有权很重要, 开发中经常碰到的就是所有权问题, 特别是用到异步和多线程的时候; 当然这也是rust保证程序正确的一个很重要的手段, 一开始不太适应, 要逼着自己思考和组织数据, 熟悉了之后就好了.另外所有权问题涉及到切片Slice, 主要用在传参和字符串, 需要掌握和熟练使用.

1.2 枚举

rust的枚举相比c++有个很大的特点是可以包含更多内容, 方便组织数据. OptionResult是rust中广泛使用的枚举类型. 枚举常常和模式匹配配合使用, 使rust的程序逻辑在编译阶段就尽量保证穷举所有情况.

1.3 字符串

要记得rust的字符串是用utf8存储的, 要区分开String, &str, [u8] 这些数据类型.

1.4 错误处理

很重要, 如果没有特别的需求,可以不用自己定义错误类型, 但经常要在函数调用的时候传递错误, 建议了解和使用anyhow这个crate,方便错误传递.如果要自己定义,建议使用thiserror.

1.5 泛型,trait

泛型要了解, 重要的是trait, 有时候这两个会弄混–学的时候不会,用的时候就模糊了. 泛型是编译时分发, trait算是动态分发.另外用到第三方库的时候, 也有很多接口是用trait给出的, 看接口文档的时候要记得看看实现了哪些trait.

1.6 生命周期

第一个应用程序可以不用自己写生命周期, 完全依赖复制和借用就行. 但也要了解一下.

1.7 迭代器和闭包

迭代器很多方法定义在Iterator这个trait中, 建议浏览一遍,很多有用的. 闭包要掌握, 很多地方都会用到.

1.8 多线程和异步

我是直接用了tokio, 会同时涉及到多线程和异步, 实现异步运行时依赖的async/await,Future,Waker这些可以先不管, 先了解tokio几个基本概念和select的用法, 多运行多调试多重构, 这是个麻烦的过程,但是必经之路.

2 第三方库

lib.rs是第三方库集合,但这里很多,有时候也不知道到底要找哪个. 这里列一下用到的一些第三方库.

2.1 tokio

rust的异步运行时. rust语言本身只提供了async/await支持, 标准库提供了Future用于实现运行时的统一接口, tokio则提供了异步运行时本身和最终的用户接口. 网络程序的话,建议直接学tokio, 绕不开的.

里边很重要的是tokio::sync::Mutexstd::sync::Mutex的区别, tokio::sync::{mpsc, oneshot, broadcast}几个通道的使用, select的使用(这个相当重要).

2.2 clap

命令行解析库.

2.3 tracing

配合tokio的日志库. clia-tracing-config是个方便的工具库, 用于方便初始化tracing日志库.

2.4 serde, toml, serde_json

serde是序列化接口, toml用于解析配置文件, serde_json用于json操作.

2.5 rdkafka

kafka的rust接口.

2.6 prost, prost-build

protobuf的rust接口. prost-build用于在编译之前从.proto文件生成.rs数据接口.

2.7 bytes

方便操作二进制数据的库, 最开始用过deku, 但deku的问题是还不够灵活,特别是处理字段间关联会很麻烦. 还不如自己用bytes直接操作这段内存.

2.8 hex

主要用于打印二进制数据, hex::encode() 将字节编码成十六进制字符串, hex::decode()从十六进制字符串解码出原始字节.

2.9 chrono

方便的 时间格式化工具.

2.10 sqlx

支持mysql, sqlite, postgres连接池, 支持tokio异步.

2.11 redis

支持redis异步.

2.12 axum

方便集成web api, 支持异步.

2.13 scopeguard

提供defer!, 用于异步时的范围资源清理.

2.14 anyhow, thiserror

前者用于错误传递,后者用于自定义错误.

2.15 criterion

替换cargo提供的性能测试框架.

3 总结

rust在保证大部分场景是安全高效的情况下,会把一些怪异的情况堆积到角落,比如Pin, unsafe这些, 进而出现很复杂的语法,才能安抚编译器, 但对我的第一个应用来说, 没有(直接)使用这些东西也完成正常功能了.

用完rust,最大的感觉是安心, 很少运行时错误,大部分在编译阶段就被发现,或者被语言本身的机制所规避. 单元测试框架也很方便, 重构后也比c++更有信心, 总之心智负担小, 算是快爬到**”愚昧之巅”**了.