You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

49 lines
6.2 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Features示例
以下我们一起来看看一些来自真实世界的示例。
### 最小化构建时间和文件大小
如果一些包的部分特性不再启用,就可以减少该包占用的大小以及编译时间:
- [`sync`](https://crates.io/crates/syn) 包可以用来解析 Rust 代码,由于它很受欢迎,大量的项目都在引用,因此它给出了[非常清晰的文档](https://docs.rs/syn/1.0.54/syn/#optional-features)关于如何最小化使用它包含的 `features`
- [`regex`](https://crates.io/crates/regex) 也有关于 features 的[描述文档](https://docs.rs/regex/1.4.2/regex/#crate-features),例如移除 Unicode 支持的 feature 可以降低最终生成可执行文件的大小
- [`winapi`](https://crates.io/crates/winapi) 拥有[众多 features](https://github.com/retep998/winapi-rs/blob/0.3.9/Cargo.toml#L25-L431),这些 `feature` 对用了各种 Windows API你可以只引入代码中用到的 API 所对应的 feature.
### 行为扩展
[`serde_json`](https://crates.io/crates/serde_json) 拥有一个 [`preserve_order` feature](https://github.com/serde-rs/json/blob/v1.0.60/Cargo.toml#L53-L56),可以用于在序列化时保留 JSON 键值队的顺序。同时,该 feature 还会启用一个可选依赖 [indexmap](https://crates.io/crates/indexmap)。
当这么做时,一定要小心不要破坏了 SemvVer 的版本兼容性,也就是说:启用 feature 后,代码依然要能正常工作。
### no_std支持
一些包希望能同时支持 [`no_std`](https://doc.rust-lang.org/stable/reference/names/preludes.html#the-no_std-attribute) 和 `std` 环境,例如该包希望支持嵌入式系统或资源紧张的系统,且又希望能支持其它的平台,此时这种做法是非常有用的,因为标准库 `std` 会大幅增加编译出来的文件的大小,对于资源紧张的系统来说,`no_std` 才是最合适的。
[wasm-bindgen](https://crates.io/crates/wasm-bindgen) 定义了一个 [std feature](https://github.com/rustwasm/wasm-bindgen/blob/0.2.69/Cargo.toml#L25),它是[默认启用的](https://github.com/rustwasm/wasm-bindgen/blob/0.2.69/Cargo.toml#L25)。首先,在库的顶部,它[无条件的启用了 `no_std` 属性](https://github.com/rustwasm/wasm-bindgen/blob/0.2.69/src/lib.rs#L8),它可以确保 `std` 和 [`std prelude`](https://doc.rust-lang.org/stable/std/prelude/index.html) 不会自动引入到作用域中来。其次,在不同的地方([示例1](https://doc.rust-lang.org/stable/std/prelude/index.html)[示例2](https://github.com/rustwasm/wasm-bindgen/blob/0.2.69/src/lib.rs#L67-L75)),它通过 `#[cfg(feature = "std")]` 启用 `std` feature 来添加 `std` 标准库支持。
## 对依赖库的features进行再导出
从依赖库再导出 features 在有些场景中会相当有用,这样用户就可以通过依赖包的 features 来控制功能而不是自己去手动定义。
例如 [`regex`](https://crates.io/crates/regex) 将 [`regex_syntax`](https://github.com/rust-lang/regex/blob/1.4.2/regex-syntax/Cargo.toml#L17-L32) 包的 features 进行了[再导出](https://github.com/rust-lang/regex/blob/1.4.2/Cargo.toml#L65-L89),这样 `regex` 的用户无需知道 `regex_syntax` 包,但是依然可以访问后者包含的 features。
## feature优先级
一些包可能会拥有彼此互斥的 features(无法共存,上一章节中有讲到),其中一个办法就是为 feature 定义优先级,这样其中一个就会优于另一个被启用。
例如 [`log`](https://crates.io/crates/log) 包,它有[几个 features](https://github.com/rust-lang/log/blob/0.4.11/Cargo.toml#L29-L42) 可以用于在编译期选择最大的[日志级别](https://docs.rs/log/0.4.11/log/#compile-time-filters),这里,它就使用了 [`cfg-if`](https://crates.io/crates/cfg-if) 的方式来[设置优先级](https://github.com/rust-lang/log/blob/0.4.11/src/lib.rs#L1422-L1448)。一旦多个 `features` 被启用,那更高优先级的就会优先被启用。
## 过程宏包
一些包拥有过程宏,这些宏必须定义在一个独立的包中。但是不是所有的用户都需要过程宏的,因此也无需引入该包。
在这种情况下,将过程宏所在的包定义为可选依赖,是很不错的选择。这样做还有一个好处:有时过程宏的版本必须要跟父包进行同步,但是我们又不希望所有的用户都进行同步。
其中给一个例子就是 [serde](https://crates.io/crates/serde) ,它有一个 [derive](https://github.com/serde-rs/serde/blob/v1.0.118/serde/Cargo.toml#L34-L35) feature 可以启用 [serde_derive](https://crates.io/crates/serde_derive) 过程宏。由于 `serde_derive` 包跟 `serde` 的关系非常紧密,因此它使用了[版本相同的需求](https://github.com/serde-rs/serde/blob/v1.0.118/serde/Cargo.toml#L17)来保证两者的版本同步性。
## 只能用于nightly的feature
Rust 有些实验性的 API 或语言特性只能在 nightly 版本下使用,但某些使用了这些 API 的包并不想强制他们的用户也使用 `nightly` 版本,因此他们会通过 feature 的方式来控制。
若用户希望使用这些 API 时,需要启用相应的 feature ,而这些 feature 只能在 nightly 下使用。若用户不需要使用这些 API就无需开启 相应的 feature自然也不需要使用 nightly 版本。
例如 [`rand`](https://crates.io/crates/rand) 包有一个 [simd_support](https://github.com/rust-random/rand/blob/0.7.3/Cargo.toml#L40) feature 就只能在 nightly 下使用,若我们不使用该 feature则在 stable 下依然可以使用 `rand`
## 实验性feature
有一些包会提前将一些实验性的 API 放出去,既然是实验性的,自然无法保证其稳定性。在这种情况下,通过会在文档中将相应的 features 标记为实验性,意味着它们在未来可能会发生大的改变(甚至 minor 版本都可能发生)。
其中一个例子是 [async-std](https://crates.io/crates/async-std) 包,它拥有一个 [unstable feature](https://github.com/async-rs/async-std/blob/v1.8.0/Cargo.toml#L38-L42),用来[标记一些新的 API](https://github.com/async-rs/async-std/blob/v1.8.0/src/macros.rs#L46),表示人们已经可以选择性的使用但是还没有准备好去依赖它。