7 个版本 (4 个重大变更)
0.5.0 | 2024 年 7 月 9 日 |
---|---|
0.4.0 | 2021 年 4 月 24 日 |
0.3.0 | 2021 年 4 月 1 日 |
0.2.1 | 2021 年 3 月 12 日 |
0.1.1 | 2021 年 1 月 9 日 |
#682 in 命令行工具
每月下载量 79
1MB
1K SLoC
sfw-tools
设计
秉承《软件工具》的精神,目标是使组件以三种方式可重用
- 将核心功能实现为函数,以便在 Rust 中重用。这些函数通常返回一个
Result
类型,以便调用者可以决定如何处理错误。 - 具有简单接口的可执行命令,通常作为库函数的薄包装,或者以有趣的方式组合库函数。
- 以及设计良好的代码,在必要时可以复制和重用。
可以探索第四种途径,即采用 nushell 方法在命令之间传输表格数据。
有关另一个遵循《软件工具》在 Rust 中实施的项目,并且可能作为一个有趣的比较,请参阅 Sweater。一个功能更丰富的项目是 uutils coreutils,如名称所示,它是一个类似于 GNU Coreutils 的 Rust 实现。
功能设施
高阶函数(HOFs)经常被用来减少代码的复杂性、冗长性和错误的风险。主要的例子是 map
、for_each
(类似于 map
但有副作用)和 fold
。正如《软件工具》第 21 页所指出的,“最好的程序是以松散耦合的函数设计的,每个函数都执行一个简单的任务”。
一些反映函数式编程价值观的其他参考资料
- 第 36 页,关于
break
的讨论:建议也与递归函数相一致。 - 第 44-45 页讨论了通过安全检查保护控制变量来进行防御性编程。在函数式编程中,这样的控制变量通常不会出现,因此由于 HOFs 的设计是安全的,因此不需要安全检查。第 45 页还指出,非冗长的代码列表更容易调试(我同意这一点,函数式风格通常可以实现这一点),尽管我们也想警告人们不要使代码过于简洁。在这方面,经验是最好的指南。
当前实现工具
-
cp
-
wc
-
detab
-
entab
-
echo
-
compress
-
expand
依赖项
由于目标是使软件尽可能自我包含且具有说明性,我们尽量依赖很少的依赖项。以下存在一些例外
- fp-core 这通常在函数式语言的常规库中找到,所以我们在这里包含它。虽然Rust在某种程度上是函数式的——它有lambda函数(即Rust闭包)并且标准库有许多高阶函数(HOFs)——但其标准库不包括在函数式语言中常见到的有助抽象的特质。我们将特别说明或合理的情况下使用其中的一些,但将坚持使用惯用的Rust,因为这显然更简单。一个有趣的现象是,过滤器是第2章和本书大部分内容的主旨,它们只是HOFs的一个特定类别。
- peeking_take_while 一个提供
peeking_take_while
函数的Peekable
迭代器的库。与标准take_while
实现相比,这个库表现得更为符合预期,后者在take_while
模式结束时“丢失”第一个元素。 - tailcall 这是一个宏,它可以为尾递归函数启用尾调用消除。换句话说,我们有时可以只写一个调用自身的函数,而不是写循环。如果没有这个宏,这样的函数最终会导致堆栈爆炸。
- seahorse Seahorse 是一个最小化参数解析器。根据一些Google搜索结果,clap 比较受欢迎,但它有额外的依赖项;我们力求尽可能的便携性,所以最小化似乎与这个目标一致。此外,Clap似乎不允许直接传递参数列表,这对于维护基于其他命令构建的独立命令很有用。无论如何,参数解析仅在应用逻辑的后期使用,并且大多数API可以在不担心它的前提下使用。
目前未使用
- byteorder 用于读取/写入大端和小端数字的库。这是一个相对底层的库,但作为这个IO密集型工具库,依赖它可能是有意义的。
- im 对于大型数据类型,实现结构共享的不可变数据结构甚至可能比
std
的可变结构表现更佳,而且虽然Rust使修改远比大多数语言更安全,但有时修改仍会导致混淆,所以在清晰度比性能更重要(或性能不是很重要,例如单操作)的情况下,可能更倾向于使用不可变数据结构。
构建
杂项笔记
使用 todo!() 的方法
使用来自 std::todo
的 todo!()
是在开发功能的同时从编译器获取反馈的有用方式。[待办事项:显示示例]
一个 警告 是,目前您需要在 todo!()
之后的函数中包含代码,即使它不匹配类型。例如,我们可以使用这样的函数
pub fn some_num() -> i32 {
todo!(); ();
}
最有益的是,如果代码中留下了todo!()
,rustc
会警告你,因为如果执行到这个路径,就会导致程序崩溃。
Rust on nix
nix develop
优化大小
目前,要生成小型构建,需要以下命令。
- (每个环境只一次) 使标准库的源代码可用
rustup component add rust-src --toolchain nightly
cargo +nightly build -Z build-std --target x86_64-unknown-linux-gnu --release
- (可选)
strip
二进制文件 - 请参阅注释中的链接
项目管理
Git 钩子
Cargo-Husky
我们使用cargo-husky来保持一致;它通过pre-push
钩子强制执行多个检查。有时它可能有点限制性,所以如果我们需要将正在进行的工作推送到分支,我们可以使用git push --no-verify -u origin feature_branch
。Cargo-husky期望某些文件位于存储库的根目录,因此使用了符号链接。
pre-commit
我们包括以下不那么严格的pre-commit检查。
#!/bin/sh
# Put in your Rust repository's .git/hooks/pre-commit to ensure you never
# breaks rustfmt.
#
# WARNING: rustfmt is a fast moving target so ensure you have the version that
# all contributors have.
for FILE in `git diff --cached --name-only`; do
if [[ -f "$FILE" ]] && [[ $FILE == *.rs ]] \
&& ! rustup run nightly rustfmt --unstable-features \
--skip-children $FILE; then
echo "Commit rejected due to invalid formatting of \"$FILE\" file."
exit 1
fi
done
cd Rust/sfw-tools && cargo readme > README.md && git add README.md
如你所见,这也从lib.rs
中的文档注释生成了README。
许可证:MPL-2.0
依赖项
~2MB
~46K SLoC