Rust学习之Features
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
特研究
相关文章:

Rust学习之Features
Rust学习之Features 一 什么是 Features二 默认 feature三 简单的features应用示例四 可选(optional)的依赖五 依赖的特性5.1 在依赖表中指定5.2 在features表中指定 六 命令行中特性控制七 特性统一路径八 其它8.1 相互排斥特性8.2 观察启用特性8.3 Feature resolver version …...

云计算基础(云计算概述)
目录 一、云计算概述 1.1 云计算的概念 1.1.1 云计算解决的问题 1.1.2 云计算的概念 1.1.3 云计算的组成 1.2 云计算主要特征 1.2.1 按需自助服务 1.2.2 泛在接入 1.2.3 资源池化 1.2.4 快速伸缩性 1.2.5 服务可度量 1.3 云计算服务模式 1.3.1 软件即服务(Softwar…...

【机器学习】科学库使用手册第2篇:机器学习任务和工作流程(已分享,附代码)
本系列文章md笔记(已分享)主要讨论人工智能相关知识。主要内容包括,了解机器学习定义以及应用场景,掌握机器学习基础环境的安装和使用,掌握利用常用的科学计算库对数据进行展示、分析,学会使用jupyter note…...

【React】前端项目引入阿里图标
【React】前端项目引入阿里图标 方式11、登录自己的iconfont-阿里巴巴矢量图标库,把需要的图标加入到自己的项目中去;2、加入并进入到项目中去选择Font class 并下载到本地3、得到的文件夹如下4. 把红框中的部分粘贴到自己的项目中(public 文…...

Javascript入门:第三个知识点:javascript里的数据类型、运算符
数字类型 123 //整数 123.1 //浮点数 1.123e3 //科学计数法 -10 //负数 NaN //not a number Infinity //无限大 以上的类型在javascript里都是数字类型 字符串类型 在开始之前,我需要先说明白两个知识点: console.log()是啥? let 与 v…...

最新版国产会声会影2024新功能爆料
会声会影2024是一个视频编辑软件,具备以下功能: 会声会影2024安装包下载如下: https://wm.makeding.com/iclk/?zoneid55677 1. 视频剪辑:可以对视频进行剪辑、裁剪、拼接和分割操作,实现对视频片段的精确控制。 2. 音频编辑&…...
Pandas处理Excel文件的实用指南 - Python开发技巧XI
处理Excel文件是数据分析师日常工作中的常见任务之一。 幸运的是,Python的Pandas库提供了一套强大的工具,使得读取、处理和写入Excel文件变得既清晰又快捷。 在本篇博客中,我们将探讨如何使用Pandas的 read_excel 方法来读取Excel文件&#x…...

泰克示波器(TBS2000系列)触发功能使用讲解——边沿触发
# Trigger区域 触发区域用于对触发功能进行配置。示波器的触发功能用于采集(Acquire)那些在瞬间出现的信号,便于我们分析观察,此时可以当做逻辑分析仪使用。触发区域按钮包括:menu、Level\Force Trig三个。 目录 1.1 …...

C++学习Day01之C++对C语言增强和扩展
目录 一、程序及输出1.1 全局变量检测增强1.2 函数检测增强1.3 类型转换检测增强1.4 struct增强1.5 bool类型扩展1.6 三目运算符增强1.7 const增强1.7.1 全局Const对比1.7.2 局部Const对比1.7.3 Const变量初始化数组1.7.3 Const修饰变量的链接性 二、分析总结 一、程序及输出 …...

【文件上传WAF绕过】<?绕过、.htaccess木马、.php绕过
🍬 博主介绍👨🎓 博主介绍:大家好,我是 hacker-routing ,很高兴认识大家~ ✨主攻领域:【渗透领域】【应急响应】 【python】 【VulnHub靶场复现】【面试分析】 🎉点赞➕评论➕收藏…...

flutter如何实现省市区选择器
前言 当我们需要用户填写地址时,稳妥的做法是让用户通过“滚轮”来滑动选择省份,市,区,此文采用flutter的第三方库来实现这一功能,比调用高德地图api简单一些。 流程 选择库 这里我选择了一个最近更新且支持中国的…...
Python——将Pyaudio的frame音频数据转换成wave格式
要将pyaudio捕获的音频帧(frame)数据转换成wave模块可以直接处理的格式,通常意味着你需要将这些音频帧数据组装成一个完整的音频流,并确保它们以wave模块期望的格式进行存储。但是,如果你的目的是将这些帧数据直接转换…...

Vue 上门取件时间组件
本文使用vue2.0elementui 制作一个上门取件时间组件,类似顺丰,样式如下: 大概功能:点击期望上门时间,下面出现一个弹框可以选择时间: 首先我们定义一些需要的数据: data() {return {isDropdown…...
学习python第一天
1.输出 print("Hello, World!") 2.退出命令提升符 exit() 3.Python 缩进 实例 if 5 > 2:print("Five is greater than two!") 空格数取决于程序员,但至少需要一个。 您必须在同一代码块中使用相同数量的空格,否则 Python 会…...
interface转string输出打印
文章目录 前言一、interface 转json再转string二、使用类型判断 前言 在开发过程中,有时我们使用interface类型接受某些参数接口或返回类型,但输出时,比如记录日志时存在很多不方便情况,输出string发现输出的乱七八糟,…...

如何在PS5上使用金手指修改游戏
环境:windows PS5 问题:PS5 没有GodHen,无法使用json金手指,PKG金手指比较少 解决办法:使用MultiTrainerv从网络注入PS5,修改进程内存 背景:为了护肝,拒绝刷刷刷 解决过程ÿ…...
M1芯片MAC 安装MySQL、Nacos遇到的问题
摘要:由于电脑上是M1芯片,安装软件时遇到一系列问题,记录下踩的坑!!! 安装MySQL MySQl官网下载链接区分ARM和X86架构,终端输入uname -a指令,本机显示为ARM czhczhdeiMac ~ % uname…...

尝试创建若依系统项目(vue3+element-plus+vite) 持续更新...
若依官网:RuoYi 若依官方网站 |后台管理系统|权限管理系统|快速开发框架|企业管理系统|开源框架|微服务框架|前后端分离框架|开源后台系统|RuoYi|RuoYi-Vue|RuoYi-Cloud|RuoYi框架|RuoYi开源|RuoYi视频|若依视频|RuoYi开发文档|若依开发文档|Java开源框架|Java|Spri…...

Pytest测试用例参数化
pytest.mark.parametrize(参数名1,参数名2...参数n, [(参数名1_data1,参数名2_data1...参数名n_data1),(参数名1_data2,参数名2_data2...参数名n_data2)]) 场景: 定义一个登录函数test_login,传入参数为name,password,需要用多个账号去测试登录功能 # …...
【Vue】指令之显示切换,属性绑定
Vue指令【2】 显示切换与属性绑定v-show指令v-if指令v-bind指令 显示切换与属性绑定 v-show指令 作用:根据真假切换元素的显示状态 指令后的内容最终都会解析为布尔值数据改变之后,对应元素的显示状态会同步更新 语法: <div id"…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...
django blank 与 null的区别
1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是,要注意以下几点: Django的表单验证与null无关:null参数控制的是数据库层面字段是否可以为NULL,而blank参数控制的是Django表单验证时字…...
Python网页自动化Selenium中文文档
1. 安装 1.1. 安装 Selenium Python bindings 提供了一个简单的API,让你使用Selenium WebDriver来编写功能/校验测试。 通过Selenium Python的API,你可以非常直观的使用Selenium WebDriver的所有功能。 Selenium Python bindings 使用非常简洁方便的A…...
WEB3全栈开发——面试专业技能点P4数据库
一、mysql2 原生驱动及其连接机制 概念介绍 mysql2 是 Node.js 环境中广泛使用的 MySQL 客户端库,基于 mysql 库改进而来,具有更好的性能、Promise 支持、流式查询、二进制数据处理能力等。 主要特点: 支持 Promise / async-await…...