Rust之构建命令行程序(一):接受命令行参数
开发环境
- Windows 10
- Rust 1.73.0
- VS Code 1.84.2
项目工程
这次创建了新的工程minigrep.
IO工程:构建命令行程序
这一章回顾了到目前为止你所学的许多技能,并探索了一些更标准的库特性。我们将构建一个与文件和命令行输入/输出交互的命令行工具,来实践一些您现在已经熟悉的Rust概念。
Rust的速度、安全性、单一二进制输出和跨平台支持使其成为创建命令行工具的理想语言,因此对于我们的项目,我们将制作自己版本的经典命令行搜索工具grep(全局搜索正则表达式并打印)。在最简单的用例中,grep在指定的文件中搜索指定的字符串。为此,grep将文件路径和字符串作为其参数。然后,它读取文件,在文件中找到包含字符串参数的行,并打印这些行。
同时,我们将展示如何让我们的命令行工具使用许多其他命令行工具使用的终端功能。我们将读取一个环境变量的值,以允许用户配置我们工具的行为。我们还将把错误消息打印到标准错误控制台流(stderr)而不是标准输出(stdout ),例如,用户可以将成功的输出重定向到一个文件,同时仍然可以在屏幕上看到错误消息。
Rust社区成员Andrew Gallant已经创建了一个功能齐全、速度非常快的grep版本,名为ripgrep。相比之下,我们的版本会相当简单,但是本章会给你一些背景知识,你需要了解一个现实世界的项目,如ripgrep。
接受命令行参数
让我们创建一个新的项目,一如既往,cargo new。我们称我们的项目为minigrep,以区别于您系统中可能已经有的grep工具。
$ cargo new minigrepCreated binary (application) `minigrep` project
$ cd minigrep
第一个任务是让minigrep接受它的两个命令行参数:文件路径和要搜索的字符串。也就是说,我们希望能够用cargo run运行我们的程序,两个连字符表示下面的参数是我们的程序而不是cargo,一个要搜索的字符串,以及一个要搜索的文件的路径,如下所示:
$ cargo run -- searchstring example-filename.txt
现在,由cargo new生成的程序无法处理我们给它的参数。crates.io上的一些现有库可以帮助编写一个接受命令行参数的程序,但是因为您刚刚学习这个概念,所以让我们自己实现这个功能。
读参数值
为了使minigrep能够读取我们传递给它的命令行参数的值,我们需要Rust的标准库中提供的std::env::args函数。该函数返回传递给minigrep的命令行参数的迭代器。我们将在后续章节全面讨论迭代器。现在,你只需要知道迭代器的两个细节:迭代器产生一系列的值,我们可以在迭代器上调用collect方法,把它变成一个集合,比如一个vector,包含迭代器产生的所有元素。
示例12-1中的代码允许您的minigrep程序读取传递给它的任何命令行参数,然后将这些值收集到一个向量中。
文件名:src/main.rs
use std::env;fn main() {let args: Vec<String> = env::args().collect();dbg!(args);
}
示例12-1:将命令行参数收集到一个向量中并打印出来
首先,我们用use语句将std::env模块纳入范围,这样我们就可以使用它的args函数。注意,std::env::args函数嵌套在两层模块中。正如我们在前面的章节中所讨论的,在期望的函数嵌套在多个模块中的情况下,我们选择将父模块而不是函数引入作用域。通过这样做,我们可以轻松地使用std::env中的其他函数。这也比添加use std::env::args,然后只使用args调用函数更明确,因为args可能很容易被误认为是当前模块中定义的函数。
args函数和无效的Unicode
请注意,如果任何参数包含无效的Unicode,std::env::args将会死机。如果您的程序需要接受包含无效Unicode的参数,请改用std::env::args_os。该函数返回一个迭代器,它产生OsString值而不是String值。为了简单起见,我们在这里选择使用std::env::args,因为OsString值因平台而异,并且比String值更复杂。
在main的第一行,我们调用env::args,并立即使用collect将迭代器转换为包含迭代器产生的所有值的向量。我们可以使用collect函数创建多种集合,因此我们显式地注释args的类型,以指定我们需要一个字符串向量。虽然我们很少需要在Rust中注释类型,但是collect是一个你经常需要注释的函数,因为Rust不能推断出你想要的集合类型。
最后,我们使用调试宏打印向量。让我们尝试先不带参数运行代码,然后带两个参数:
$ cargo runCompiling minigrep v0.1.0 (file:///projects/minigrep)Finished dev [unoptimized + debuginfo] target(s) in 0.61sRunning `target/debug/minigrep`
[src/main.rs:5] args = ["target/debug/minigrep",
]
$ cargo run -- needle haystackCompiling minigrep v0.1.0 (file:///projects/minigrep)Finished dev [unoptimized + debuginfo] target(s) in 1.57sRunning `target/debug/minigrep needle haystack`
[src/main.rs:5] args = ["target/debug/minigrep","needle","haystack",
]
注意,向量中的第一个值是“target/debug/minigrep”,这是我们的二进制文件的名称。这与C中参数列表的行为相匹配,允许程序使用在执行过程中被调用的名称。如果您想在消息中打印程序名,或者根据调用程序时使用的命令行别名来更改程序的行为,那么访问程序名通常会很方便。但是为了本章的目的,我们将忽略它,只保存我们需要的两个参数。
将参数值保存在变量中
该程序目前能够访问指定为命令行参数的值。现在我们需要将两个参数的值保存在变量中,这样我们就可以在程序的其余部分使用这些值。我们在示例12-2中这样做了。
文件名:src/main.rs
use std::env;fn main() {let args: Vec<String> = env::args().collect();let query = &args[1];let file_path = &args[2];println!("Searching for {}", query);println!("In file {}", file_path);
}
示例12-2:创建变量来保存查询参数和文件路径参数
正如我们在打印vector时看到的,程序名在args[0]处占用了vector中的第一个值,所以我们从索引1处开始参数。minigrep获取的第一个参数是我们要搜索的字符串,所以我们在变量query中引用了第一个参数。第二个参数将是文件路径,因此我们将对第二个参数的引用放在变量file_path中。
我们临时打印这些变量的值,以证明代码按照我们的预期工作。让我们用参数test和sample.txt再次运行这个程序:
$ cargo run -- test sample.txtCompiling minigrep v0.1.0 (file:///projects/minigrep)Finished dev [unoptimized + debuginfo] target(s) in 0.0sRunning `target/debug/minigrep test sample.txt`
Searching for test
In file sample.txt
太好了,程序工作了!我们需要的参数值被保存到正确的变量中。稍后我们将添加一些错误处理来处理某些潜在的错误情况,比如当用户没有提供参数时;现在,我们将忽略这种情况,转而添加文件读取功能。
本章重点
- 构建命令行程序的概念
- 如何构建命令行程序
- 如何通过程序读取参数值
- 如何通过程序讲参数值保存在变量中
相关文章:

Rust之构建命令行程序(一):接受命令行参数
开发环境 Windows 10Rust 1.73.0 VS Code 1.84.2 项目工程 这次创建了新的工程minigrep. IO工程:构建命令行程序 这一章回顾了到目前为止你所学的许多技能,并探索了一些更标准的库特性。我们将构建一个与文件和命令行输入/输出交互的命令行工具&#…...

Go 谈论了解Go语言
一、引言 Go的历史回顾 Go语言(通常被称为Go或Golang)由Robert Griesemer、Rob Pike和Ken Thompson在2007年开始设计,并于2009年正式公开发布。这三位设计者都曾在贝尔实验室工作,拥有丰富的编程语言和操作系统研究经验。Go的诞生…...

《C++PrimerPlus》第9章 内存模型和名称空间
9.1 单独编译 Visual Studio中新建头文件和源代码 通过解决方案资源管理器,如图所示: 分成三部分的程序(直角坐标转换为极坐标) 头文件coordin.h #ifndef __COORDIN_H__ // 如果没有被定义过 #define __COORDIN_H__struct pola…...

uniapp上架app store详细攻略
目录 uniapp上架app store详细攻略 前言 一、登录苹果开发者网站 二、创建好APP 前言 uniapp开发多端应用,打包ios应用后,会生成一个ipa后缀的文件。这个文件无法直接安装在iphone上,需要将这个ipa文件上架app store后,才能通…...
面试:线上问题处理
文章目录 在处理线上问题时,你的排查思路和步骤是什么线上偶发性问题如何处理和跟踪当系统出现大量错误日志时,你会如何分析和解决问题在高并发场景中,如何排查和解决线程安全问题当系统出现大规模的故障时,你的应急处理和恢复策略…...
Vue3中快速Diff算法
在Vue3中,快速Diff算法主要用于优化虚拟DOM的更新过程,减少不必要的DOM操作,提高性能。以下是对Vue3源码中快速Diff算法的解读: 首先,我们需要引入Vue3的相关包: import { reactive, toRefs, watch } fro…...

ROS2+STM32小车红外对射光电计数器模块资料
数据:一个周长内有20个孔洞或者20个分隔。外径:6.8cm 图片不是实物图,是示意图 因为没有串口,所以不可能会发送出数字的,就是通过电压变化次数来计算距离或者其他数据 有遮挡时,输出高电平,无遮…...

Android设计模式--桥接模式
闻正言,行正道,左右前后皆正人 一,定义 将抽象部分与实现部分分离,使它们都可以独立地进行变化 二,使用场景 从模式的定义中,我们大致可以了解到,这里的桥接的作用其实就是连接抽象部分与实现…...

1、分布式锁实现原理与最佳实践(一)
在单体的应用开发场景中涉及并发同步时,大家往往采用Synchronized(同步)或同一个JVM内Lock机制来解决多线程间的同步问题。而在分布式集群工作的开发场景中,就需要一种更加高级的锁机制来处理跨机器的进程之间的数据同步问题&…...
Autosar通信实战系列03-NM模块要点及其配置介绍
本文框架 前言1. NM模块要点介绍1.1 NM基本功能介绍1.2 NM协同功能介绍2. NM配置2.1 NmGlobalConfig配置2.2 NmChannelConfigs配置前言 在本系列笔者将结合工作中对通信实战部分的应用经验进一步介绍常用,包括但不限于通信各模块的开发教程,代码逻辑分析,调测试方法及典型问…...
Golang模块管理功能
文章目录 1. Golang 包管理1.1 GOPATH 包管理1.2 Go vendor 包管理1.3 Go modules包管理2. Go Modules 应用实践2.1 Go modules关键信息2.1.1 go mod 命令行2.1.2 配置代理服务2.2 创建项目2.3 获取依赖包2.4 运行项目1. Golang 包管理 1.1 GOPATH 包管理 第一阶段: Golang初…...

从零构建属于自己的GPT系列1:文本数据预处理、文本数据tokenizer、逐行代码解读
🚩🚩🚩Hugging Face 实战系列 总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在PyCharm中进行 本篇文章配套的代码资源已经上传 从零构建属于自己的GPT系列1:文本数据预处理 从零构建属于自己的GPT系列2:语…...

scipy 笔记:scipy.spatial.distance
1 pdist 计算n维空间中观测点之间的成对距离。 scipy.spatial.distance.pdist(X, metriceuclidean, *, outNone, **kwargs) 1.1 主要参数 X一个m行n列的数组,表示n维空间中的m个原始观测点metric使用的距离度量out输出数组。如果非空,压缩的距离矩阵…...
java video audio encoder
引言 在现代互联网的时代,视频和音频已经成为人们生活中不可或缺的一部分。而在计算机科学中,视频和音频编码器则是将原始的视频和音频数据转换为可压缩格式的关键技术。在本文中,我们将探讨基于Java的视频和音频编码器的使用。 什么是视频…...
TypeScript 中声明类型的方法
1、使用:运算符来为变量和函数参数指定类型。例如: let num: number 5; function add(a: number, b: number): number {return a b; }2、使用 type 关键字来声明自定义类型别名。例如: type Point {x: number;y: number; };3、使用 interface 关键字…...

显示器校准软件BetterDisplay Pro mac中文版介绍
BetterDisplay Pro mac是一款显示器校准软件,可以帮助用户调整显示器的颜色和亮度,以获得更加真实、清晰和舒适的视觉体验。 BetterDisplay Pro mac软件特点 - 显示器校准:可以根据不同的需求和环境条件调整显示器的颜色、亮度和对比度等参数…...
Element UI 走马灯 实现鼠标滚动切换页面
鼠标滚动切换页面 elementui Carousel 走马灯鼠标滚轮事件实现 一、在轮播图外的盒子外添加鼠标滚轮事件,触发GoWheel函数。 wheel"goWheel"二、通过判断deltaY的数值来触发相应事件 它检查滚轮事件的deltaY属性是否大于0 event.deltaY当鼠标滚轮向下…...
在Docker上部署Springboot项目
在Docker上部署Springboot项目 ###1.安装docker 2.安装mysql 拉 Mysql 镜像 docker pull mysql:5.7.31运行 Mysql 5.7.31 第一次运行需要设置密码 docker run -d --name myMysql -p 9506:3306 -v /data/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD1234 mysql:5.7.31不是…...
2024中国眼博会,全国眼康与眼镜品牌加盟展会,北京眼健康展
立足北京,面向全球,2024第六届CEYEE中国眼博会,将以大规模的展览面积在4月与您相会; ——春天是万物复苏的季节,更是企业开拓市场,抓住春季发展机遇的重要时节;第六届CEYEE中国眼博会将在2024年…...
C++学习 --谓词
目录 1, 什么是谓词 1-1, 一元谓词 1-2, 二元谓词 1, 什么是谓词 返回bool类型的仿函数, 叫着谓词, 分为一元谓词和二元谓词 1-1, 一元谓词 operator()接收一个参数,叫着一元谓…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

基于Springboot+Vue的办公管理系统
角色: 管理员、员工 技术: 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能: 该办公管理系统是一个综合性的企业内部管理平台,旨在提升企业运营效率和员工管理水…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?
在工业自动化持续演进的今天,通信网络的角色正变得愈发关键。 2025年6月6日,为期三天的华南国际工业博览会在深圳国际会展中心(宝安)圆满落幕。作为国内工业通信领域的技术型企业,光路科技(Fiberroad&…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...