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

news2024/9/28 11:22:57

开发环境

  • 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 minigrep
     Created 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 run
   Compiling minigrep v0.1.0 (file:///projects/minigrep)
    Finished dev [unoptimized + debuginfo] target(s) in 0.61s
     Running `target/debug/minigrep`
[src/main.rs:5] args = [
    "target/debug/minigrep",
]

$ cargo run -- needle haystack
   Compiling minigrep v0.1.0 (file:///projects/minigrep)
    Finished dev [unoptimized + debuginfo] target(s) in 1.57s
     Running `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.txt
   Compiling minigrep v0.1.0 (file:///projects/minigrep)
    Finished dev [unoptimized + debuginfo] target(s) in 0.0s
     Running `target/debug/minigrep test sample.txt`
Searching for test
In file sample.txt

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

本章重点

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

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

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

相关文章

一文带你读懂骨传导耳机危害性都有哪些!以及如何选择骨传导耳机!

如果说正常的使用骨传导耳机&#xff0c;是不会有危害的。 那么如何正确的使用骨传导耳机呢&#xff1f; 1、音量不要太大 骨传导耳机是通过震动人体骨骼来传递声音的&#xff0c;而在传递过程中&#xff0c;会出现漏音情况&#xff0c;而漏出的声音&#xff0c;便会通过耳道…

打破障碍:克服数字化应用挑战的策略

通过正确的方法&#xff0c;企业可以成功地克服复杂性&#xff0c;并从数字化中获益。 数字技术的出现彻底改变了我们的生活和工作方式。从智能手机到社交媒体&#xff0c;数字工具在我们的日常生活中无处不在。对于许多个人和组织而言&#xff0c;采用数字技术可能是一个重大…

关于数据中心机房防雷和接地系统的解决方案

随着通信技术、计算机网络技术的飞速发展&#xff0c;计算机和网络越来越深入人们生活和工作中&#xff0c;同时也预示着数字化、信息化时代的来临。由于微电子设备具有高密度、高速度、低电压、和低功耗等特性&#xff0c;极易受雷击、电磁脉冲辐射、地电位反击、电源尖波等瞬…

常见加密算法

常见加密算法 加密算法是一种用数学方法对数据进行变换的技术&#xff0c;目的是保护数据的安全&#xff0c;防止被未经授权的人读取或修改。加密算法可以分为三大类&#xff1a;对称加密算法、非对称加密算法和哈希算法&#xff08;也叫摘要算法&#xff09;。 哈希算法 哈…

事务的状态和ACID特性

事务就是让数据从一个状态到另一个状态的操作 状态 活动的 事务在执行过程中 部分提交的 事务的最后一个操作已经完成&#xff0c;此时造成的影响只是在内存里&#xff0c;但还没刷写磁盘 失败的 处于活动的或者部分提交的状态时&#xff0c;服务器宕机 中止的 处于失败…

2023-简单点-机器学习中矩阵向量求导

机器学习中矩阵向量求导的概念是什么&#xff1f; 在机器学习中&#xff0c;矩阵向量求导的概念主要涉及对函数中的矩阵或向量参数进行求导运算。这种求导运算可以帮助我们了解函数值随参数的变化情况&#xff0c;进而应用于优化算法中。具体来说&#xff0c;当损失函数是一个…

【Mybatis系列】Mybatis之TypeHandler入门

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

asp.net mvc游戏门户网站

c#asp.net mvc 说明文档 运行前附加数据库.mdf&#xff08;或sql生成数据库&#xff09; 主要技术&#xff1a; 基于asp.net mvc架构和sql server数据库&#xff0c;并采用EF实体模型开发三层架构BLL DAL 功能模块&#xff1a; 前端展示首页 新闻公告 英雄档案 视频图片 管理…

oracle FUNCTION(任意两个时间 之间的工作小时)

写函数计算 任意两个时间 之间的工作小时 每天工作时间&#xff08;8:00 - 20:00 共12小时&#xff09;&#xff0c;没有休息日 CREATE OR REPLACE FUNCTION SC_YD_DESI.CALCULATE_WORK_HOURS_FUNC (p_current_time IN DATE,p_order_time IN DATE ) RETURN NUMBER ASp_work_hou…

萤石云接口调用

获取appKey和secret 登录后在开发者服务-我的应用中获取 根据appKey和secret获取accessToken 参考官方文档&#xff1a;文档概述 萤石开放平台API文档 # 获取accessToken url_accessToken"https://open.ys7.com/api/lapp/token/get" data {"appKey": &…

选择aspera替代方案的理由,有哪些aspera替代方案

Aspera是一种快速数据传输协议和工具&#xff0c;它使用高效的UDP协议和复杂的流控制算法来实现可靠、高速的数据传输。该协议和工具广泛应用于媒体和娱乐行业、金融服务和其他需要大规模数据传输的领域。然而&#xff0c;Aspera的高昂价格和限制性许可证可能使得某些企业寻找替…

2022年全国硕士研究生入学统一考试管理类专业学位联考英语(二)试题

文章目录 2022年全国硕士研究生招生考试英语&#xff08;二&#xff09;试题Section I Use of EnglishSection II Reading ComprehensionText 12122232425 Text 22627282930 Text 33132333435 Text 43637383940 Section III TranslationSection III WritingPart APart B 2022年…

Python 爬虫 案例 之 豆瓣Top250电影数据

前言 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 如果有什么疑惑/资料需要的可以点击文章末尾名片领取源码 课程亮点&#xff1a; 1、动态数据抓包演示 2、csv文件保存 3、requests模块的使用 4、parsel解析数据的使用 环境介绍&#xff1a; python 3.8 pycharm 模块…

在线陪诊系统: 医学科技的革新之路

医疗服务的数字化时代已经到来&#xff0c;而在线陪诊系统正是医学科技革新的杰出代表。通过巧妙的技术代码&#xff0c;这一系统不仅实现了患者和医生之间的远程互动&#xff0c;还将医疗服务推向了一个更加智能化的未来。在这篇文章中&#xff0c;我们将深入探讨在线陪诊系统…

ASP.NET Core Web API设置响应输出的Json数据格式的两种方式

前言 在ASP.NET Core Web API中设置响应输出Json数据格式有两种方式&#xff0c;可以通过添加System.Text.Json或Newtonsoft.JsonJSON序列化和反序列化库在应用程序中全局设置接口响应的Json数据格式&#xff0c;本文示例使用的是新的Minimal API模式。 JSON序列化和反序列化库…

Labview Lite Note

目录 001十六进制字符串转浮点数002浮点数转十六进制字符串 001十六进制字符串转浮点数 002浮点数转十六进制字符串

森林无人机高效解决巡查难题,林区防火掀新篇

山东省某市为了强化森林火灾防范&#xff0c;采用了一项新兴手段——复亚智能无人机森林火情监测系统。这套系统在AI飞行大脑的指挥下&#xff0c;让无人机在空中巡逻&#xff0c;实现了无人机森林防火系统的实施落地。 一、AI大脑如何引领森林无人机高空巡逻&#xff1f; 在山…

区块链存证:杭州互联网法院备选方案之一

文章目录 背景上报的存证系统设计备选方案***总体原则******分层架构******基础节点******存证链******存证业务******存证接入******通用功能******跨链对接架构***业务流程描述用户发起原创内容存证&#xff08;对应上图中左边1,2,3活动&#xff09;发现侵权行为&#xff0c;…

迷你洗衣机哪个牌子好又实惠?小型洗衣机质量排名

随着大家工作的压力越来越大&#xff0c;下了班之后只能想躺平&#xff0c;在洗完澡之后看着还需要手洗的内衣裤真的很头疼。有些小伙伴还有会攒几天再丢进去洗衣机里面一起&#xff0c;而且这样子是非常不好的&#xff0c;用过的内衣裤长时间不清洗容易滋生细菌&#xff0c;而…

HCIP-九、路由控制

九、路由控制 实验拓扑实验需求及解法1.企业生产网运行 OSPF&#xff0c;完成以下需求&#xff1a;2.数据中心运行 ISIS3.路由引入4.路由策略5.策略路由6.ISP 过滤私网路由 实验拓扑 实验需求及解法 1.企业生产网运行 OSPF&#xff0c;完成以下需求&#xff1a; 1.1 OSPF 进程…