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中。 

我们临时打印这些变量的值,以证明代码按照我们的预期工作。让我们用参数testsample.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

太好了,程序工作了!我们需要的参数值被保存到正确的变量中。稍后我们将添加一些错误处理来处理某些潜在的错误情况,比如当用户没有提供参数时;现在,我们将忽略这种情况,转而添加文件读取功能。

本章重点

  • 构建命令行程序的概念
  • 如何构建命令行程序
  • 如何通过程序读取参数值
  • 如何通过程序讲参数值保存在变量中

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/177929.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

业务流程图用什么软件绘制?

在企业的日常工作中&#xff0c;对于业务流程的把控和优化显得非常重要。为了更好地理解和管理业务流程&#xff0c;业务流程图便应运而生。 业务流程图是企业管理的图形化工具&#xff0c;它描述了企业在生产和服务提供过程中&#xff0c;在各个环节中所涉及的各种操作、任务…

python如何抓取携程酒店的价格,让工作更简单点

有时候老板没事安排点事&#xff0c;为了偷懒&#xff0c;只能使出大招&#xff0c;毕竟自己不是那么老老实实干活的人&#xff0c;整理数据这类累和繁琐的活&#xff0c;我怎么能轻易动&#xff0c;好在gpt可以帮我来实现&#xff0c;有人可能会说&#xff0c;这么点内容你还不…

OpenCvSharp从入门到实践-(05)通道

目录 1、拆分通道 1.1、实例1-拆分一副BGR图像的通道 1.2、实例2-拆分一副HSV图像的通道 2、合并通道 2.1 实例3-合并通道的顺序不同&#xff0c;图像的显示效果也不通 实例4-合格H通道图像、S通道图像、V通道图像 3、综合运用拆分通道和合并通道 2.2、实例5-只把H通道的…

Vue3-admin-template 导入模板功能

先看效果&#xff1a; 直接上代码&#xff1a; 1.绑定事件&#xff1a; <el-button type"primary" click"templates">模板导入</el-button> 2.写结构样式 <!-- 模板导入 --><el-dialog v-model"Statusimprot" title&quo…

js相同字符串截取拼接

原数据 const list [999-1234567801,999-1234567802,999-1234567803, ]; const list1 [999-1234567899,999-1234567900,999-1234567901, ];期望数据 999-1234567801/2/3 //list 999-1234567899/900/901 //list1处理代码 // 连续号码处理 export const formatNumber (tick…

9.二维数组——打印出杨辉三角形(要求打印出10行)

文章目录 前言一、题目描述 二、题目分析 三、解题 程序运行代码 前言 本系列为二维数组编程题&#xff0c;点滴成长&#xff0c;一起逆袭。 一、题目描述 打印出杨辉三角形&#xff08;要求打印出10行&#xff09;。 二、题目分析 三、解题 程序运行代码 #include<s…

在柯桥西班牙语论文写作,连接词只会用porquepero?西语连接词大全来啦~

Adicin -agregan nuevos datos al desarrollo de una idea o introduce otro aspecto del tema. 为观点的论述增添新的信息&#xff0c;或介绍主题的另一个方面。 1 Lista de conectores 连接词列表 Adems. As mismo. Hay que mencionar, adems. Habra que decir tambin. Mas …

[算法总结] - 蓄水池采样算法

问题描述 在长度为N的数组中&#xff0c;随机等概率选取K个元素&#xff0c;如何实现这个随机算法。 思路很简单&#xff0c;生成一个[0, N]的随机数index&#xff0c;然后返回index上的数值即可。 但是&#xff0c;如果输入是一个长度未知的数组比如stream&#xff0c;先遍历…

JUC(Java.util.concurrent)的常见类

目录 ♫ReentrantLock ♪什么是ReentrantLock ♪ReentrantLock的用法 ♪ReentrantLock和synchronized的区别 ♫Semaphore ♪什么是Semaphore ♪semaphore的用法 ♫CountDownLatch ♪什么是CountDownLatch ♪CountDownLatch的使用 ♫多线程环境使用ArrayList ♫多线程环…

数据分享 I 重点城市现状建筑数据,shp格式放送

数据名称: 现状建筑数据 数据格式: Shp 数据时间: 不同城市的数据时间有所不同&#xff0c;详情可搜“吧唧数据” 数据几何类型: 面 数据坐标系: WGS84坐标系 数据来源&#xff1a;网络公开数据 深圳市现状建筑数据示意图 东莞市部分镇街现状建筑数据示意图 武汉市部…

深入了解MySQL数据库管理与应用

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交流的小伙伴&#xff0c;请点击【全栈技术交流群】 当涉及MySQL数据库管理与应用时&#xff0c;深…

【Cisco Packet Tracer】构造超网

​​&#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《Cisco Packet Tracer | 奇遇记》⏰寄 语&#xff1a;风翻云浪激&#xff0c;剑舞星河寂。 临风豪情壮志在&#xff0c;拨云见日昂首立。 目录 ⛳️1. Cisco Packet Trace…

在数据库中进行表内容的修改(MYSQL)

根据表中内容&#xff0c;用命令语句创建数据库&#xff0c;表格&#xff0c;以及插入&#xff0c;修改&#xff0c;删除表格中的内容。 创建数据库&#xff1a;zrzy mysql> create database zrzy; 引用zrzy数据库&#xff1a; mysql> use zrzy; 创建student_info表&…

vulnhub靶机gigachad_vh

下载地址&#xff1a;Gigachad: 1 ~ VulnHub 主机发现 目标166 端口扫描 端口服务扫描 漏洞扫描 这玩意多得离谱 于是我用a重新扫了一遍 先去看web (⊙﹏⊙)离谱&#xff0c;目录扫描&#xff08;之前先去看一下nmap扫到的html&#xff09; 后面扫描的目录奇多&#xff0c;而…

NX二次开发UF_MTX3_x_vec 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_MTX3_x_vec Defined in: uf_mtx.h void UF_MTX3_x_vec(const double mtx [ 9 ] , double x_vec [ 3 ] ) overview 概述 Returns the X-direction vector of a matrix. 返回矩阵…

uniapp地图基本使用及解决添加markers不生效问题?

uniapp地图使用 App端 通过 nvue 页面实现地图 文章目录 uniapp地图使用效果图templatejs添加 marker使用地图查看位置移到到当前位置 效果图 template <template><view class"mapWrap"><!-- #ifdef APP-NVUE --><map class"map-containe…

springboot自定义更换启动banner动画

springboot自定义更换启动banner动画 文章目录 springboot自定义更换启动banner动画 &#x1f4d5;1.新建banner&#x1f5a5;️2.启动项目&#x1f516;3.自动生成工具&#x1f9e3;4.彩蛋 &#x1f58a;️最后总结 &#x1f4d5;1.新建banner 在resources中新建banner.txt文…

my.ini添加了一句后又删除了,重启却失败的解决办法

背景&#xff1a;添加了一句&#xff0c;然后保存了&#xff0c;之后打开删掉了&#xff0c;结果就无法启动了&#xff0c;最后另存为ANSI格式&#xff0c;再把这个格式文件覆盖my.ini即可解决

商品软文怎么写?媒介盒子教你三步

想要把产品卖出去&#xff0c;除了保证产品质量外&#xff0c;还可以通过线上推广来提高产品销量&#xff0c;而商品文案就是线上推广中的重要因素&#xff0c;今天媒介盒子就来和大家聊聊&#xff0c;怎么写好商品软文。 商品软文想要写好主要分为三要素&#xff1a;痛点、卖…

C++相关闲碎记录(1)

1、C绘制爱心图像 #include <iostream> #include <cmath>using namespace std;int main() {// 心形曲线公式 (x^2 y^2 - a)^3 - x^2*y^3 0double a 1;double bound 1.5 * sqrt(a);double step 0.05;for (double y bound; y > -bound; y - step) {for (do…