网站设计需要哪些,成品网站1688入口的功能介绍,wordpress管理页面中文,扬中最近最新事件Rust学习之Features 一 什么是 Features二 默认 feature三 简单的features应用示例四 可选(optional)的依赖五 依赖的特性5.1 在依赖表中指定5.2 在features表中指定 六 命令行中特性控制七 特性统一路径八 其它8.1 相互排斥特性8.2 观察启用特性8.3 Feature resolver version … Rust学习之Features 一 什么是 Features二 默认 feature三 简单的features应用示例四 可选(optional)的依赖五 依赖的特性5.1 在依赖表中指定5.2 在features表中指定 六 命令行中特性控制七 特性统一路径八 其它8.1 相互排斥特性8.2 观察启用特性8.3 Feature resolver version 2 本文是学习Solana 程序库合约SPL的Rust 预先知识部分需要有Rust基础 本文学习课程为https://doc.rust-lang.org/cargo/reference/features.html 。下面的内容为一些简单记录。
下面的内容中feature和特性会交叉出现但是均指同一概念。
一 什么是 Features
Features 是用来表达条件编译或者条件依赖的机制。
定义在Cargo.toml中的[features]表中的features 可以启用或者不启用。在构建时通过命令行参数--features来启用需要的特性作为依赖启用特性时直接在Cargo.toml中定义。
基本的features块定义为
[features]
# Defines a feature named webp that does not enable any other features.
webp []在Rust中使用webp特性的代码示例
// This conditionally includes a module which implements WEBP support.
#[cfg(feature webp)]
pub mod webp;// 下面是不启用no-entrypoint才包含entrypoint模块的定义
#[cfg(not(feature no-entrypoint))]
mod entrypoint;特性可以包含其它特性
[features]
bmp []
png []
ico [bmp, png]
webp []// 注意下面bmp和png的定义顺序任意可以放在ico的下面二 默认 feature
默认程序时不启用任何特性的但是我们可以定义程序默认启用的features
[features]
default [ico, webp]
bmp []
png []
ico [bmp, png]
webp []三 简单的features应用示例
接着上面的Cargo.toml定义一个简单的应用示例:
fn main() {#[cfg(feature webp)]println!(Hello webp!);#[cfg(not(feature webp))]println!(Hello not webp!);#[cfg(feature ico)]println!(Hello ico!);#[cfg(feature gif)]println!(Hello gif!);
}运行结果如下
$ cargo run
Hello not webp!
Hello ico!$ cargo run --features webp
Hello webp!
Hello ico!默认时仅启用了default未启用所以上面cargo run输出了ico。
注意就算指定了--features参数默认特性还是会启用。关闭它有两种方法:
命令行参数使用--no-default-features作为依赖库在定义时设定default-features false选项。
因此我们如果在cargo run时不想启用默认特性运行如下命令:
$ cargo run --features webp --no-default-features
Hello webp!注意原文提到了要小心默认特性设置它通常启用了一些方便用户使用常用功能。但万一用户不想启用这些功能时需要在所有依赖定义中限定default-features false.特别当一个包被多处依赖时每处定义都要指定default-features false.
四 可选(optional)的依赖
依赖库也可以标记为optional它意味着默认情况下不会被编译。例如如下定义
[dependencies]
gif { version 0.11.1, optional true }默认时gif依赖是未启用的那怎么启用它呢其实上面的定义同时隐式定义了一个gif特性类似如下定义
[features]
gif [dep:gif]当然我们无需手动写出上面的定义但是如果你不想使用默认名称和库名相同就得手写一个了如果你手写了那么隐式特性就不存在了。例如如下示例
[dependencies]
ravif { version 0.6.3, optional true }
rgb { version 0.8.25, optional true }[features]
avif [dep:ravif, dep:rgb]上面的定义中用户只能选择avif特性阻止用户单独选择ravif或者rgb因为也许这两者是必须同时启用的。
切记采用上面的方式时依赖必须是optional。
五 依赖的特性
5.1 在依赖表中指定
在定义外部依赖的同时还可以同时指定启用的特性例如
[dependencies]
# Enables the derive feature of serde.
serde { version 1.0.118, features [derive] }
flate2 { version 1.0.3, default-features false, features [zlib] }注意上面提到过就算指定了依赖的features不是feature因为可以指定启用多个特性所以为一数组是带复数的s其默认特性依然是开启的因此我们必须手动关掉它正如flate2定义。当然如果别的地方同时也用到了flate2那么无法保证其默认特性是关闭的前面提到过原因。
5.2 在features表中指定
依赖的特性也可以在features表中定义上面的是在dependencies表中定义语法为package-name/feature-name,示例如下:
[dependencies]
jpeg-decoder { version 0.1.20, default-features false }[features]
# Enables parallel processing support by enabling the rayon feature of jpeg-decoder.
parallel [jpeg-decoder/rayon]可以看到这种方式定义时关闭默认特性还是在dependencies表中进行。
注意当依赖为可选依赖时package-name/feature-name语法还会同时启用该依赖然而有时你却不想这么做那么可以使用如下语法
package-name?/feature-name 。这样只有在其它别处启用该依赖后定义的特性才会被启用。示例如下:
[dependencies]
serde { version 1.0.133, optional true }
rgb { version 0.8.25, optional true }[features]
serde [dep:serde, rgb?/serde]上面的定义中启用serde特性会启用 serde 依赖库但是只有在其它地方启用rgb依赖库了它才会启用rgb的serde特性例如我们定义了一个新的特性其它即启用了rgb又包含了上面定义的serde特性。
(下面代码未验证仅为个人猜想
[features]
serde [dep:serde, rgb?/serde]
all [dep:rgb,serde]六 命令行中特性控制 --features FEATURES: 指定启用的特性注意可以指定多个特性它是一个列表使用逗号或者空格分隔。如果使用空格分隔注意在所有特性整体名称上加上双引号。例如我们接最初的toml及程序定义运行示例 $ cargo run --features webp gif
Hello webp!
Hello ico!$ cargo run --features webp gif
Hello webp!
Hello ico!
Hello gif!// 下面webp,gif中逗号前后可以有空格
$ cargo run --features webp,gif --no-default-features
Hello webp!
Hello gif!--all-features: 启用所有特性 --no-default-features: 不启用默认特性
七 特性统一路径
当一个依赖在多个包中使用时Cargo会使用所有启用特性的统一路径来标记它从而确保只有一份单一的代码被使用无重复代码。
如下图所示 此时构建my-package时会启用winapi的四个特性。
特性中有一个共识是增加性也就是启用一个特性不会关闭已有的功能并且任意特性之间都可以联合使用。
例如 当你想支持no_std环境时不要使用no_std特性不要做减法而是使用一个std特性来启用std库。示例代码如下
#![no_std]#[cfg(feature std)]
extern crate std;#[cfg(feature std)]
pub fn function_that_requires_std() {// ...
}上面的代码中如果启用std特性就使用std库同时启用相应的函数。在revm Rust EVM实现中能见到大量这种用法因为区块链运行环境并不一定支持std所以统一使用#![no_std].
八 其它
8.1 相互排斥特性
通常不要这么设计因为在确保任意特性联合都可以安全使用但万一存在两个排斥特性时需要进行检测并给出编译错误例如
#[cfg(all(feature foo, feature bar))]
compile_error!(feature \foo\ and feature \bar\ cannot be enabled at the same time);三种替代方案为:
分离不同功能到不同的包使用其中一个包替换另一个重构代码消除排斥性特性。
8.2 观察启用特性
cargo tree命令可以观察哪些特性被启用了主要有这么几种用法
cargo tree -e features: 待研究cargo tree -f {p} {f}: 待研究cargo tree -e features -i foo: 待研究
8.3 Feature resolver version 2
Feature resolver version 2
特研究