网站建设投标ppt模板,cms适合做什么网站,建个人网站,html在线编辑网站开发环境
Windows 10Rust 1.73.0 VS Code 1.84.2 项目工程
这次创建了新的工程minigrep. IO工程#xff1a;构建命令行程序
这一章回顾了到目前为止你所学的许多技能#xff0c;并探索了一些更标准的库特性。我们将构建一个与文件和命令行输入/输出交互的命令行工具#…开发环境
Windows 10Rust 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: VecString env::args().collect();dbg!(args);
}
示例12-1:将命令行参数收集到一个向量中并打印出来
首先我们用use语句将std::env模块纳入范围这样我们就可以使用它的args函数。注意std::env::args函数嵌套在两层模块中。正如我们在前面的章节中所讨论的在期望的函数嵌套在多个模块中的情况下我们选择将父模块而不是函数引入作用域。通过这样做我们可以轻松地使用std::env中的其他函数。这也比添加use std::env::args然后只使用args调用函数更明确因为args可能很容易被误认为是当前模块中定义的函数。 args函数和无效的Unicode 请注意如果任何参数包含无效的Unicodestd::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: VecString 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太好了程序工作了我们需要的参数值被保存到正确的变量中。稍后我们将添加一些错误处理来处理某些潜在的错误情况比如当用户没有提供参数时现在我们将忽略这种情况转而添加文件读取功能。
本章重点
构建命令行程序的概念如何构建命令行程序如何通过程序读取参数值如何通过程序讲参数值保存在变量中