rust语言_学习笔记
转载注明来源: 本文链接 来自osnosn的博客,写于 2023-12-10.
安装 rust
cargo 的 config 设置
- 更换 ustc 源,使用代理。设置缺省registry。见【rust cargo 配置】。
crate库
-
搜索
- cli 命令行参数解析 【clap】
应该还有更简单小巧的库。【Collected benchmarks for arg parsing crates written in Rust】- getopt, 基本符合POSIX参数解析规则。似乎仅支持短参数。
- getopt3, 符合GNU参数解析规则。似乎仅支持短参数。
- clap_lex,用两个循环去match。短参数支持合并写法 "-ab"。
- 【lexopt】可用,和libc中的getopt很像。短参数支持合并写法 "-ab"。
还可以通过 bin_name() 获取当前的程序名。执行文件自身的名称。 - xflags,用声明宏。 "-a -b"不支持合并写法 "-ab"。
- argh,用自定义宏(#derive). "-a -b"不支持合并写法 "-ab"。
- gumdrop,挺高级的。
- pico-args,似乎不好用。
- 异步,多线程
- 【tokio】
- json解析
- 【tidwall/gjson.rs】
- serde_json
【Rust中JSON如何解析转换到struct】
【Rust序列化、反序列化方案:Serde】,【Serde序列化/反序列化模块】,【Serde序列化/反序列化模块】
- bincode 二进制序列化/反序列化
【二进制自压缩序列化bincode模块】
或者,rust标准库的u32::from_le_bytes()
,123_u32.to_le_bytes()
,f32::from_le_bytes()
,12.3_f32.to_le_bytes()
, - image库
- sqlite3
- 【rusqulite】可用。需要安装
apt install libsqlite3-dev
。
如果要静态编译,或编译window程序,Cargo.toml 中要加入features = ["bundled"]
(gnu 相关的交叉编译都OK。musl 相关的交叉编译,都会失败,没找到解决办法)
多线程中使用,每个线程单独建立一个连接(Connection::open())就行,要求sqlite-3.7.0以上。【1】【2】【3】
会碰到,编译器无法确定泛型的具体类型,需要用 turbofish语法,在调用函数时指定类型。- 用到的函数,
Connection::open(),execute(),query_row(),prepare(),close(),
Statement::execute(),insert(),query(),query_map(),exists(),query_row(),finalize(),
Row::get(),
Rows::next(),map(),get(),...
- 用到的函数,
- 【sqlite3】
- 【rusqulite】可用。需要安装
- 读取 ini文件
- light_ini, ini_core, tini,
- 【ini_lib】 简单,可用
- gui
- iced
- fltk
- 需要 cmake-3.15.0 以上。
- 交叉编译x86_64-pc-windows-gun, i686-pc-windows-gnu 成功。
在 main.rs第一行,加入#![windows_subsystem = "windows"]
,运行时不会出现console窗口。 - 其他的target编译失败。可能是缺少 libx...的包。
- 在aarch64的UOS中编译,cmake版本太低,编译失败。
- 把文件/目录打包到执行文件中
- embed 太旧,用不了
- 【rust-embed-for-web】 可用
- rust-embed
- 获取Utc,Local时间,
*用use chrono::{Local, Utc};
- 在openwrt中,Local时间的获取, 依赖 /etc/localtime 文件。
如果localtime文件不存在,则获取的是Utc时间。
这个表现,和golang获取Local时间是一样的。 - time v0.2.27
- 在openwrt中,Local时间的获取, 依赖 /etc/localtime 文件。
- base64 编码解码, base64_light
- 正则, regex::Regex
- 文件/路径/目录 操作, std::path:Path
- 文件读取, std::fs
- memmap2 文件的内存映射。
- bzip2 压缩
- 时间计算, std:time::Duration
- hdf5
- mlua
- features: lua54 需要
apt install lua5.4 liblua5.4-dev
Cargo.toml 中加入features= ["lua54","vendored"]
,在debian x86_64 rustc-1.74中,交叉编译,全部成功。(2024-03测)RUSTFLAGS='-C target-feature=+crt-static' cargo build --release --target x86_64-unknown-linux-gnu RUSTFLAGS='-C target-feature=+crt-static' cargo build --release --target x86_64-unknown-linux-musl TARGET_CC=i686-w64-mingw32-gcc RUSTFLAGS='-C target-feature=+crt-static' cargo build --release --target i686-pc-windows-gnu TARGET_CC=x86_64-w64-mingw32-gcc RUSTFLAGS='-C target-feature=+crt-static' cargo build --release --target x86_64-pc-windows-gnu TARGET_CC=aarch64-linux-gnu-gcc RUSTFLAGS='-C linker=aarch64-linux-gnu-gcc -C target-feature=+crt-static' cargo build --release --target aarch64-unknown-linux-gnu #使用openwrtSDK,交叉编译mipsel-musl #成功#
- features: luajit 或 luajit52 需要
apt install luajit2 libluajit2-5.1-dev
Cargo.toml 中加入features= ["luajit52","vendored"]
,在debian x86_64 rustc-1.74中,交叉编译,部分失败。(2024-03测)RUSTFLAGS='-C target-feature=+crt-static' cargo build --release --target x86_64-unknown-linux-gnu #失败#RUSTFLAGS='-C target-feature=+crt-static' cargo build --release --target x86_64-unknown-linux-musl #失败#TARGET_CC=i686-w64-mingw32-gcc RUSTFLAGS='-C target-feature=+crt-static' cargo build --release --target i686-pc-windows-gnu TARGET_CC=x86_64-w64-mingw32-gcc RUSTFLAGS='-C target-feature=+crt-static' cargo build --release --target x86_64-pc-windows-gnu TARGET_CC=aarch64-linux-gnu-gcc RUSTFLAGS='-C linker=aarch64-linux-gnu-gcc -C target-feature=+crt-static' cargo build --release --target aarch64-unknown-linux-gnu #使用openwrtSDK,交叉编译mipsel-musl #失败#
- features: luau 好像不需要额外安装。
- userdata 参考【userdata.rs】,【mlua-userdata-json】,【How to store functions in UserData】
- features: lua54 需要
Rust中文文档
- 看其中的【Rust 程序设计语言】,好难。
- rust语言 本身似乎不复杂,"所有权"也不难理解。
- "泛型",也好理解。"生命周期",也好理解。
- "Trait",比较复杂,没看明白做啥用的。
- "宏"好复杂。又是一种独立的语法。
包含,用macro_rules!的声明宏,和三种过程宏 (自定义宏 #[derive],类属性宏,类函数宏)。
笔记
创建项目
- 修改
~/.cargo/config
。更换 ustc 源,使用代理。设置缺省registry。见【rust cargo 配置】。 - 选择一个目录,
cargo new lexopt-test
创建一个项目。看【cargo-new(1)】 - 搜索 crate,
cargo search lexopt
,看【cargo-search(1)】 - 添加 crate "lexopt"
- 方法1:执行
cargo add lexopt
,看【cargo-add(1)】
会自动获取最新的版本,并写入 Cargo.toml- 删除create,执行
cargo remove lexopt
- 查看本项目使用的crate,
cargo tree
- 删除create,执行
- 方法2:在 docs.rs 中搜索 lexopt,找到它的版本号。
手工修改 Cargo.toml,在[dependencies]
下面,插入一行,
lexopt = "0.3.0"
然后执行cargo update
,把这个crate 拉取下来。- 删除crate,编辑 Cargo.toml 删除lexot那行。执行
cargo update
即可。
- 删除crate,编辑 Cargo.toml 删除lexot那行。执行
- 方法1:执行
- 编写
src/main.rs
使用这个 crate。
从 【lexopt】 抄它的 example。 cargo clean
清理缓存。cargo check
检查。cargo fmt
格式化源码文件。cargo build
编译。cargo vendor pkg
把当前项目依赖的所有包,下载到当前目录的pkg目录中。
不要下载到 ./ 当前目录,会把当前目录中的所有文件清空。
rust 中引入其他rs文件
- 【rsut基础:模块的使用一、mod 关键字、mod.rs 文件的含义等】
- 【Rust 引入其他的 rs 文件】
- 其他:【了解下Rust 模块使用方式】,【rust 模块管理中的 mod 和 use】,【关于Rust模块系统的清晰解释】,【使用include!来引入其它rs文件中的方法】
-
例子,对ini_lib包不满意, 拉下来修改一下用
cargo vendor pkg
把包拉下来放到pkg目录中。
mv pkg/ini_lib ./
把包目录移出来。
修改当前项目的Cargo.toml
按需修改 ./ini_lib/src/lib.rs 即可。[dependencies] #把这行注释# ini_lib = { version = "0.1.4", registry = "rsproxy" } ini_lib = { path = "./ini_lib" }
编程中的问题记录
-
出现
note: #[warn(non_snake_case)] on by default
警告。
你的项目名称不是蛇形命名。即不是 "单词+下划线+单词" 的命名方式。
在 src/main.rs 的第一行加入#![allow(non_snake_case)]
允许非蛇形命名,即可。 -
查找标准库的functions或methods, 去 【doc.rust-lang.org/std】搜索
搜 Some 或 Option,就能找到很多教程中没有介绍的methods。如 ok_or(), map_or(), unwrap_or()
见,【Enum std::option::Option】,str【Primitive Type str】,【Struct std::string::String】, -
turbofish-涡轮鱼,语法
编译时报错,编译器无法确定泛型的具体类型。那么,需要用 turbofish语法,在调用函数时指定类型。
比如 sqlite的连接 conn,调用conn.query_row("select ...",[],|row| row.get(0));
会报错 cannot infer type of the type parameterT
declared on the methodget
, 编译器建议使用 row.get::<usize, T>(0)
如果返回的是String,就改为 row.get::<usize, String>(0) -
要把字符串变量传入 子线程,不能用 &str,编译会报错"life time"不够。应该用 String 或 Arc<String> 就没问题了。
-
调试变量,除了用println!(), 还可以用 dbg!()。 dbg!(用&引用变量)。
-
【发布配置 Profile】,【Cargo Book/Profiles】,
【优化 Rust 程序编译体积】,【rust 性能优化】,【Cargo使用指南|发布配置 Profile】,【最小化 Rust 二进制文件大小】,# 可以考虑这几项 [profile.release] strip = true opt-level = "s" lto = true panic = "abort" #codegen-units = 1 # 如果用了 regex的简单匹配,可以限定 features,只启用"std" features,可以减少体积。 [dependencies] regex = { version = "1.10.2", default-features = false, features = ["std"] }
-
一个项目中,教程说,可以包含多个二进制crate。
用cargo new
创建的项目(package),默认有src/main.rs
,
如果手工创建src/bin/test1.rs
,src/bin/test1.rs
,就能编译出 3个二进制程序。
如果src/bin/test1.rs
中要使用 module(模块),考虑以下方法。- 把 module 写入 src/lib.rs,test1.rs 中用 use 导入。
- 使用以下目录结构。见【Rust参考手册.标准的 Package 目录结构】.
src/bin/test1/main.rs #用 mod my_module; 引入 src/bin/test1/my_module.rs
- 使用 path 属性 做内联。见【Rust参考手册.模块】.
#[path="../my_module.rs"] mod my_module;
-
【rust course/工作空间Workspace】,【Cargo Book/Workspaces】,【知乎/workspace详解】
手动创建 Cargo.tmol[workspace] resolver="2" #Edition2021 默认为 2 members = ["pkg2", "pkg3"] #写入包含的多个项目
如果子项目中有
[profile.release]
,整个copy到 workspace目录的 Cargo.toml中。注释掉子项目中 Cargo.toml的[profile.release]
。 -
【条件编译 Features】
在代码块前加一行#[cfg(feature = "myfeature")]
或#[cfg(not(feature = "myfeature"))]
,
编译时指定了myfeature才会被选择编译。
然后在 Cargo.toml中加入:[features] myfeature = [] #如果没有相关依赖 myfeature = ["xxx1"] #如果有别的依赖 default = [] #默认不开启这个feature default = ["myfeature"] #默认开启这个feature
-
#[cfg(target_os = "windows")] { //...win代码 } #[cfg(target_os = "linux")] { //...Linux代码 } if cfg!(target_os = "windows") { // windows系统要执行的代码段 } else if cfg!(target_os = "linux") { // linux系统要执行的代码段 } #[cfg(not(target_os = "linux"))] { // 非Linux 的代码 } #[cfg(all(unix, target_pointer_width = "32"))] { // 32位 unix }
-
Cargo 为 crates 设置的环境变量
程序中用这种方式获取let version = env!("CARGO_PKG_VERSION");
【Cargo手册.环境变量】,【The Cargo Book.Environment Variables】 -
【Rust中 #[derive()]是什么?怎么理解】,【Rust 参考手册/派生 derive — 自动部署 trait实现】,【Rust 版本指南/自定义 Derive】,
【Rust 常见20类常见Trait,你熟悉多少?】,【Rust 常见内置 Traits 详解】,【[译] Rust 的内置 Traits, 使用场景, 方式, 和原因】
其他
----end----
转载注明来源: 本文链接 https://www.cnblogs.com/osnosn/p/17913222.html
来自 osnosn的博客 https://www.cnblogs.com/osnosn/ .