当前位置: 首页 > news >正文

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

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

本章重点

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

相关文章:

Rust之构建命令行程序(一):接受命令行参数

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

Go 谈论了解Go语言

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

《C++PrimerPlus》第9章 内存模型和名称空间

9.1 单独编译 Visual Studio中新建头文件和源代码 通过解决方案资源管理器&#xff0c;如图所示&#xff1a; 分成三部分的程序&#xff08;直角坐标转换为极坐标&#xff09; 头文件coordin.h #ifndef __COORDIN_H__ // 如果没有被定义过 #define __COORDIN_H__struct pola…...

uniapp上架app store详细攻略

目录 uniapp上架app store详细攻略 前言 一、登录苹果开发者网站 二、创建好APP 前言 uniapp开发多端应用&#xff0c;打包ios应用后&#xff0c;会生成一个ipa后缀的文件。这个文件无法直接安装在iphone上&#xff0c;需要将这个ipa文件上架app store后&#xff0c;才能通…...

面试:线上问题处理

文章目录 在处理线上问题时&#xff0c;你的排查思路和步骤是什么线上偶发性问题如何处理和跟踪当系统出现大量错误日志时&#xff0c;你会如何分析和解决问题在高并发场景中&#xff0c;如何排查和解决线程安全问题当系统出现大规模的故障时&#xff0c;你的应急处理和恢复策略…...

Vue3中快速Diff算法

在Vue3中&#xff0c;快速Diff算法主要用于优化虚拟DOM的更新过程&#xff0c;减少不必要的DOM操作&#xff0c;提高性能。以下是对Vue3源码中快速Diff算法的解读&#xff1a; 首先&#xff0c;我们需要引入Vue3的相关包&#xff1a; import { reactive, toRefs, watch } fro…...

ROS2+STM32小车红外对射光电计数器模块资料

数据&#xff1a;一个周长内有20个孔洞或者20个分隔。外径&#xff1a;6.8cm 图片不是实物图&#xff0c;是示意图 因为没有串口&#xff0c;所以不可能会发送出数字的&#xff0c;就是通过电压变化次数来计算距离或者其他数据 有遮挡时&#xff0c;输出高电平&#xff0c;无遮…...

Android设计模式--桥接模式

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

1、分布式锁实现原理与最佳实践(一)

在单体的应用开发场景中涉及并发同步时&#xff0c;大家往往采用Synchronized&#xff08;同步&#xff09;或同一个JVM内Lock机制来解决多线程间的同步问题。而在分布式集群工作的开发场景中&#xff0c;就需要一种更加高级的锁机制来处理跨机器的进程之间的数据同步问题&…...

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、逐行代码解读

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

scipy 笔记:scipy.spatial.distance

1 pdist 计算n维空间中观测点之间的成对距离。 scipy.spatial.distance.pdist(X, metriceuclidean, *, outNone, **kwargs) 1.1 主要参数 X一个m行n列的数组&#xff0c;表示n维空间中的m个原始观测点metric使用的距离度量out输出数组。如果非空&#xff0c;压缩的距离矩阵…...

java video audio encoder

引言 在现代互联网的时代&#xff0c;视频和音频已经成为人们生活中不可或缺的一部分。而在计算机科学中&#xff0c;视频和音频编码器则是将原始的视频和音频数据转换为可压缩格式的关键技术。在本文中&#xff0c;我们将探讨基于Java的视频和音频编码器的使用。 什么是视频…...

TypeScript 中声明类型的方法

1、使用:运算符来为变量和函数参数指定类型。例如&#xff1a; let num: number 5; function add(a: number, b: number): number {return a b; }2、使用 type 关键字来声明自定义类型别名。例如&#xff1a; type Point {x: number;y: number; };3、使用 interface 关键字…...

显示器校准软件BetterDisplay Pro mac中文版介绍

BetterDisplay Pro mac是一款显示器校准软件&#xff0c;可以帮助用户调整显示器的颜色和亮度&#xff0c;以获得更加真实、清晰和舒适的视觉体验。 BetterDisplay Pro mac软件特点 - 显示器校准&#xff1a;可以根据不同的需求和环境条件调整显示器的颜色、亮度和对比度等参数…...

Element UI 走马灯 实现鼠标滚动切换页面

鼠标滚动切换页面 elementui Carousel 走马灯鼠标滚轮事件实现 一、在轮播图外的盒子外添加鼠标滚轮事件&#xff0c;触发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中国眼博会,全国眼康与眼镜品牌加盟展会,北京眼健康展

立足北京&#xff0c;面向全球&#xff0c;2024第六届CEYEE中国眼博会&#xff0c;将以大规模的展览面积在4月与您相会&#xff1b; ——春天是万物复苏的季节&#xff0c;更是企业开拓市场&#xff0c;抓住春季发展机遇的重要时节&#xff1b;第六届CEYEE中国眼博会将在2024年…...

C++学习 --谓词

目录 1&#xff0c; 什么是谓词 1-1&#xff0c; 一元谓词 1-2&#xff0c; 二元谓词 1&#xff0c; 什么是谓词 返回bool类型的仿函数&#xff0c; 叫着谓词&#xff0c; 分为一元谓词和二元谓词 1-1&#xff0c; 一元谓词 operator()接收一个参数&#xff0c;叫着一元谓…...

OpenClaw调试进阶:百川2-13B-4bits量化模型响应日志分析

OpenClaw调试进阶&#xff1a;百川2-13B-4bits量化模型响应日志分析 1. 为什么需要关注模型响应日志 上周我在用OpenClaw对接百川2-13B-4bits量化模型时&#xff0c;遇到了一个奇怪的现象&#xff1a;自动化任务执行到一半突然中断&#xff0c;控制台只显示"模型响应异常…...

《算法竞赛从入门到国奖》算法基础:动态规划-最长子序列

&#x1f4a1;Yupureki:个人主页 ✨个人专栏:《C》 《算法》《Linux系统编程》《高并发内存池》《MySQL数据库》 《个人在线OJ平台》 &#x1f338;Yupureki&#x1f338;的简介: 目录 1. 最长上升子序列 算法原理 代码示例 2. 合唱队形 算法原理 代码示例 3. 最长公共…...

曾经我和大模型交流业务实现记录

第一次&#xff1a; 我有一组子组件11个&#xff0c;通过子组件的不同组合&#xff0c;可以组成表单&#xff0c;这些表单让不同的用户使用&#xff0c;表单组成公共的内容&#xff0c;让大部分用户使用&#xff0c;当然用户可以在这些表单的基础上修改一些默认值&#xff0c;变…...

OpenClaw多模型切换指南:Qwen3.5-9B与Llama3混合调度实战

OpenClaw多模型切换指南&#xff1a;Qwen3.5-9B与Llama3混合调度实战 1. 为什么需要多模型切换&#xff1f; 去年我在搭建个人AI工作流时&#xff0c;发现单一模型很难满足所有需求。用Qwen处理文档时效果惊艳&#xff0c;但遇到代码生成任务就显得力不从心&#xff1b;换成专…...

JAVA重点基础、进阶知识及易错点总结(14)字节流 字符流

&#x1f680; Java 巩固进阶 第14天 主题&#xff1a;字节流 & 字符流 —— 文件读写的核心引擎&#x1f4c5; 进度概览&#xff1a;今天进入 IO 流的灵魂章节&#xff01;掌握这 4 个核心类&#xff0c;你就能打通文件读写的任督二脉。 &#x1f4a1; 核心价值&#xff…...

实时信号处理中的滤波器选型实战指南:从需求分析到性能优化

实时信号处理中的滤波器选型实战指南&#xff1a;从需求分析到性能优化 【免费下载链接】gnuradio GNU Radio – the Free and Open Software Radio Ecosystem 项目地址: https://gitcode.com/gh_mirrors/gn/gnuradio 一、需求分析&#xff1a;明确滤波器设计目标 在开…...

新手入门指南:基于快马生成的代码理解设备配对功能实现

今天想和大家分享一个特别适合新手学习的设备配对功能实现案例。这个例子用最基础的HTML、CSS和原生JavaScript就能完成&#xff0c;特别适合刚接触前端开发的朋友理解交互逻辑。 项目结构设计 整个项目分为三个部分&#xff1a;两个模拟设备&#xff08;用不同图标表示&#x…...

INNISO1接口模块

INNIS01 接口模块INNIS01 是一款应用于工业自动化控制系统中的接口模块&#xff0c;主要用于实现控制系统内部或与外部设备之间的信号连接与数据交互&#xff0c;属于系统中的通信与接口扩展单元。一、基本概述INNIS01 接口模块通常用于连接控制器与现场设备或其他功能模块&…...

别再为联合仿真头疼了!手把手教你用Amesim 2019和Matlab 2022b配置S-Function(Win10环境)

从零搭建Amesim与Matlab联合仿真环境&#xff1a;避坑指南与实战技巧 联合仿真技术已成为多物理场系统设计的黄金标准&#xff0c;但配置过程却让无数工程师在深夜的办公室里抓狂——编译器版本冲突、环境变量设置错误、接口编译失败&#xff0c;每一个环节都可能成为项目进度的…...

从CVE-2025-65112到NPM投毒:手把手教你搭建安全的私有包仓库(以PubNet为例)

从CVE-2025-65112到NPM投毒&#xff1a;手把手教你搭建安全的私有包仓库&#xff08;以PubNet为例&#xff09; 最近几年&#xff0c;软件供应链攻击事件频发&#xff0c;从SolarWinds事件到Log4j漏洞&#xff0c;再到最近的NPM投毒事件&#xff0c;每一次都让开发者们心惊胆战…...