Rust处理命令行参数

概述

为了让我们的程序接收一系列数值作为命令行参数并打印出它们的最
大公约数,可以将 src/main.rs 中的 main 函数替换为以下内容:

use std::str::FromStr;
use std::env;
fn main() {let mut numbers = Vec::new();for arg in env::args().skip(1) {numbers.push(u64::from_str(&arg).expect("error parsing argument"));}if numbers.len() == 0 {eprintln!("Usage: gcd NUMBER ...");std::process::exit(1);}let mut d = numbers[0];for m in &numbers[1..] {d = gcd(d, *m);}println!("The greatest common divisor of {:?} is {}", numbers, d);
}

代码分析

use std::str::FromStr;
use std::env;

第一个 use 声明将标准库中的 FromStr 特型引入了当前作用域。

特型是可以由类型实现的方法集合。任何实现了 FromStr 特型的类型都有一个 from_str 方法,该方法会尝试从字符串中解析这个类型的值。u64 类型实现了 FromStr,所以我们将调用u64::from_str 来解析程序中的命令行参数。

尽管我们从未在程序的其他地方用到 FromStr 这个名字,但仍然要 use(使用)它,因为要想使用某个特型的方法,该特型就必须在作用域内。

第二个 use 声明引入了 std::env 模块,该模块提供了与执行环境交互时会用到的几个函数和类型,包括 args 函数,该函数能让我们访问程序中的命令行参数。

代码分析2

let mut numbers = Vec::new();

我们声明了一个可变的局部变量 numbers 并将其初始化为空向量。

Vec 是 Rust 的可增长向量类型,类似于 C++ 的 std::vector、Python 的列表或 JavaScript 的数组。虽然从设计上说向量可以动态扩充或收缩,但仍然要标记为 mut,这样 Rust 才能把新值压入末尾。

numbers 的类型是 Vec,这是一个可以容纳 u64 类型的值的向量,但和以前一样,不需要把类型写出来。Rust 会推断它,一部分原因是我们将 u64 类型的值压入了此向量,另一部分原因是我们将此向量的元素传给了 gcd,后者只接受 u64 类型的值。

代码分析3

for arg in env::args().skip(1) {

这里使用了 for 循环来处理命令行参数,依次将变量 arg 指向每个参数并运行循环体。

std::env 模块的 args 函数会返回一个迭代器,此迭代器会按需生成1每个参数,并在完成时给出提示。各种迭代器在 Rust 中无处不在,标准库中也包括一些迭代器,这些迭代器可以生成向量的元素、
文件每一行的内容、通信信道上接收到的信息,以及几乎任何有意义的循环变量。Rust 的迭代器非常高效,编译器通常能将它们翻译成与手写循环相同的代码。

除了与 for 循环一起使用,迭代器还包含大量可以直接使用的方法。例如,args 返回的迭代器生成的第一个值永远是正在运行的程序的名称。如果想跳过它,就要调用迭代器的 skip 方法来生成一个新的迭代器,新迭代器会略去第一个值。

代码分析4

numbers.push(u64::from_str(&arg).expect("error parsing argument"));

这里我们调用了 u64::from_str 来试图将命令行参数 arg 解析为一个无符号的 64 位整数。u64::from_str 并不是 u64 值上的某个方法,而是与 u64 类型相关联的函数,类似于 C++ 或 Java 中
的静态方法。

from_str 函数不会直接返回 u64,而是返回一个指明本次解析已成功或失败的 Result 值。Result 值是以下两种变体之一:

  • 形如 Ok(v) 的值,表示解析成功了,v 是所生成的值;
  • 形如 Err(e) 的值,表示解析失败了,e 是解释原因的错误
    值。

执行任何可能会失败的操作(例如执行输入或输出或者以其他方式与操作系统交互)的函数都会返回一个 Result 类型,其 Ok 变体会携带成功结果(传输的字节数、打开的文件等),而其 Err 变体会携带错误码,以指明出了什么问题。

与大多数现代语言不同,Rust 没有异常(exception):所有错误都使用 Result 或 panic 进行处理。

Golang也没有异常,作为新设计的语言,这两个语言在对错误处理的理念上非常的相似。

我们用 Result 的 expect 方法来检查本次解析是否成功。如果结果是 Err(e),那么 expect 就会打印出一条包含 e 的消息并直接退出程序。但如果结果是 Ok(v),则 expect 会简单地返回 v 本身,最终我们会将其压入这个数值向量的末尾。

代码分析5

if numbers.len() == 0 {eprintln!("Usage: gcd NUMBER ...");std::process::exit(1);
}

空数组没有最大公约数,因此要检查此向量是否至少包含一个元素,如果没有则退出程序并报错。这里我们用 eprintln! 宏将错误消息写入标准错误流。

这里eprintln的e表示的是stderr,也就是标准错误输出流。

代码分析6

let mut d = numbers[0];
for m in &numbers[1..] {d = gcd(d, *m);
}

该循环使用 d 作为其运行期间的值,不断地把它更新为已处理的所有数值的最大公约数。和以前一样,必须将 d 标记为可变,以便在循环中给它赋值。

这个 for 循环有两个值得注意的地方。首先,我们写了 for m in &numbers[1…],那么这里的 & 运算符有什么用呢?其次,我们写了 gcd(d, *m),那么 *m 中的 * 又有什么用呢?这两个细节是紧密相关的。

迄今为止,我们的代码只是在对简单的值(例如适合固定大小内存块的整数)进行操作。但现在我们要迭代一个向量,它可以是任意大小,而且可能会非常大。Rust 在处理这类值时非常慎重:它想让程序员控制内存消耗,明确每个值的生存时间,同时还要确保当不再需要这些值时能及时释放内存。

所以在进行迭代时,需要告诉 Rust,该向量的所有权应该留在numbers 上,我们只是为了本次循环而借用它的元素。

&numbers[1…] 中的 & 运算符会从向量中借用从第二个元素开始的引用。for 循环会遍历这些被引用的元素,让 m 依次借出每个元素。*m 中的 * 运算符会将 m解引用,产生它所引用的值,这就是要传给 gcd 的下一个 u64。最后,由于 numbers 拥有着此向量,因此当 main 末尾的 numbers 超出作用域时,Rust 会自动释放它。

Rust 的所有权规则和引用规则是 Rust 内存管理和并发安全的关键所在。只有熟悉了这些规则,才算熟练掌握了 Rust。但是对于这个介绍性的导览,你只需要知道&x 借用了对 x 的引用,而 *r 访问的是 r 所引用的值就足够了。

代码分析7

println!("The greatest common divisor of {:?} is {}", numbers, d);

遍历 numbers 的元素后,程序会将结果打印到标准输出流。

println! 宏会接受一个模板字符串,在模板字符串中以 {…} 形式标出的位置按要求格式化并插入剩余的参数,最后将结果写入标准输出流。

C 和 C++ 要求 main 在程序成功完成时返回 0,在出现问题时返回非零的退出状态,而 Rust 假设只要 main 完全返回,程序就算成功完成。只有显式地调用像 expect 或 std::process::exit 这样的函数,才能让程序以表示错误的状态码终止。

运行程序

cargo run 命令可以将参数传给程序,因此可以试试下面这些命令行处理:

cargo run 42 56
cargo run 83
cargo run

查看文档

本节使用了 Rust 标准库中的一些特性。如果你好奇还有哪些别的特性,强烈建议看看 Rust 的在线文档。它具有实时搜索功能,能让你的探索更容易,其中还包括指向源代码的链接。

安装 Rust 时,rustup 命令会自动在你的计算机上安装一份文档副本。

你既可以在Rust 网站上查看标准库文档,也可以使用以下命令打开浏览器查看。

rustup doc --std

实战案例1:Vec向量的基本用法

创建项目:

cargo new hello

编写代码:

cd hello
vim src/main.rs

完整代码:

fn main() {let mut numbers = Vec::new();numbers.push(11);numbers.push(22);numbers.push(33);println!("numbers = {:?}", numbers);
}

运行:

zhangdapeng@zhangdapeng:~/code/hello$ cargo runCompiling c10_func v0.1.0 (/home/zhangdapeng/code/hello)Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.91sRunning `target/debug/c10_func`
numbers = [11, 22, 33]

清理:

zhangdapeng@zhangdapeng:~/code/hello$ cargo cleanRemoved 36 files, 8.3MiB total

实战案例2:获取命令行参数

创建项目:

cargo new hello

编写代码:

cd hello
vim src/main.rs

完整代码:

use std::str::FromStr;
use std::env;fn main() {println!("args = {:?}", env::args());for arg in env::args().skip(1){println!("arg = {}", arg);println!("arg = {}", u64::from_str(&arg).expect("error parsing argument"));}
}

运行:

zhangdapeng@zhangdapeng:~/code/hello$ cargo run 11 22Compiling c10_func v0.1.0 (/home/zhangdapeng/code/hello)Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.23sRunning `target/debug/c10_func 11 22`
args = Args { inner: ["target/debug/c10_func", "11", "22"] }
arg = 11
arg = 11
arg = 22
arg = 22

清理:

zhangdapeng@zhangdapeng:~/code/hello$ cargo cleanRemoved 43 files, 8.4MiB total

实战案例3:求命令行参数的最大公约数

创建项目:

cargo new hello

编写代码:

cd hello
vim src/main.rs

完整代码:

use std::str::FromStr;
use std::env;fn gcd(mut m: u64, mut n:u64) -> u64 {assert!(m != 0 && n != 0);while n != 0 {if n < m {let t = n;n = m;m = t;}n %= m;}m
}#[test]
fn test_gcd(){assert_eq!(gcd(14, 15), 1);assert_eq!(gcd(2*3*5*11*17, 3*7*11*13*19), 3*11);
}fn main() {let mut numbers = Vec::new();for arg in env::args().skip(1){numbers.push(u64::from_str(&arg).expect("error parsing argument"));}if numbers.len() == 0{eprintln!("Usage: gcd NUMBER ...");std::process::exit(1);}let mut d = numbers[0];for m in &numbers[1..]{d = gcd(d, *m);}println!("The greatest common divisor of {:?} is {}", numbers, d);
}

测试:

zhangdapeng@zhangdapeng:~/code/hello$ cargo testCompiling c10_func v0.1.0 (/home/zhangdapeng/code/hello)Finished `test` profile [unoptimized + debuginfo] target(s) in 0.41sRunning unittests src/main.rs (target/debug/deps/c10_func-7066c0fd0fc42bb9)running 1 test
test test_gcd ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

运行:

zhangdapeng@zhangdapeng:~/code/hello$ cargo run 33 99Compiling c10_func v0.1.0 (/home/zhangdapeng/code/hello)Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.21sRunning `target/debug/c10_func 33 99`
The greatest common divisor of [33, 99] is 33

运行2:

zhangdapeng@zhangdapeng:~/code/hello$ cargo run 33Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00sRunning `target/debug/c10_func 33`
The greatest common divisor of [33] is 33

运行3:

zhangdapeng@zhangdapeng:~/code/hello$ cargo runFinished `dev` profile [unoptimized + debuginfo] target(s) in 0.00sRunning `target/debug/c10_func`
Usage: gcd NUMBER ...

清理:

zhangdapeng@zhangdapeng:~/code/hello$ cargo cleanRemoved 83 files, 15.6MiB total

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

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

相关文章

第八十一章 将 Web 应用程序与远程 Web 服务器结合使用 - 如果从 Web 服务器提供静态文件

文章目录 第八十一章 将 Web 应用程序与远程 Web 服务器结合使用 - 如果从 Web 服务器提供静态文件如果从 Web 服务器提供静态文件配置 Web 服务器路径将虚拟目录添加到 IIS将别名添加到 Apache 配置 第八十一章 将 Web 应用程序与远程 Web 服务器结合使用 - 如果从 Web 服务器…

【C++】认识C++(上)

目录 从C到C命名空间同名冲突命名空间的定义命名空间的使用 C的输入和输出缺省参数&#xff08;默认参数&#xff09; 从C到C C语言的出现是计算机科学和工程史上的一个重要里程碑&#xff0c;许多现代计算机语言都受C语言的影响。C语言是面向过程的&#xff0c;结构化和模块化…

梯度下降算法要点和难点具体应用

梯度下降算法(Gradient Descent Algorithm)是一种常用的优化算法,用于求解机器学习和深度学习中模型参数的最优解。其基本思想是通过迭代的方式,不断地沿着函数梯度的反方向更新参数,从而逼近函数的最小值点(或最大值点,取决于问题是求最小值还是最大值)。 以下是梯度下…

PostgreSQL的表空间

PostgreSQL的表空间 基础信息 OS版本&#xff1a;Red Hat Enterprise Linux Server release 7.9 (Maipo) DB版本&#xff1a;16.2 pg软件目录&#xff1a;/home/pg16/soft pg数据目录&#xff1a;/home/pg16/data 端口&#xff1a;5777在 PostgreSQL 中&#xff0c;表空间&…

力扣HOT100 - 279. 完全平方数

解题思路&#xff1a; 动态规划 class Solution {public int numSquares(int n) {int[] dp new int[n 1];// 初始化dp数组&#xff0c;默认最坏情况是每个数都是由1相加得到的for (int i 1; i < n; i) {dp[i] i;}for (int i 1; i < n; i) {for (int j 1; j * j &…

Python Twisted库:异步网络编程的利器

更多Python学习内容&#xff1a;ipengtao.com 在现代网络应用开发中&#xff0c;异步编程已经成为一种必备的技能。Python Twisted库是一款强大的异步网络编程框架&#xff0c;它提供了丰富的工具和功能&#xff0c;使得开发者可以轻松地构建高性能的网络应用。 基本概念 Twist…

在虚机VirtualBox7.0.8安装Androidx86_64系统详细步骤要点

最近需要用到安卓系统蓝牙功能做测试&#xff0c;就选择了Virtualboxandroidx86方案&#xff0c;先把系统安装好&#xff0c;后面看是否可以比较好的完成蓝牙功能测试。如果可以的话&#xff0c;我会再发文分享下的&#xff0c;敬请期待。 1.准备材料 &#xff08;1&#xff…

【aws】amazon linux使用密码登录或者root登陆

amazon linux ssh 使用密码登录 设置好安全区组规则后0.0.0.0/0,或者想安全就指定aws的ip,如果多个安全组都有绑定&#xff0c;多个安全组打开 1、使用AWS控制台创建的密钥对或者建议直接通过网页登录 注意&#xff1a;使用pem私钥不允许直接登录root用户&#xff0c;只能登…

Python API和微服务的测试库之httpretty使用详解

概要 在现代软件开发中,API和微服务的测试是确保应用稳定性和功能正确性的关键环节。Python的HTTPretty库提供了一个强大的工具,允许开发者在不实际发起网络请求的情况下模拟HTTP请求和响应。本文将全面介绍HTTPretty的安装、特性、基本与高级功能,并结合实际应用场景,展示…

企业如何利用美国多IP服务器来提升网站的安全性?

企业如何利用美国多IP服务器来提升网站的安全性? 在当前网络环境下&#xff0c;网站安全性日益成为企业面临的重要挑战。为了有效应对各种潜在威胁&#xff0c;越来越多的企业选择利用美国多IP服务器来提升其网站的安全性。这种服务器配置能够通过一系列策略来增加网站的安全…

5G NR 吞吐量计算 and 4G LTE 吞吐量计算

5G NR Throughput References • 3GPP TS 38.306 V15.2.0 (2018-06) ➤J : number of aggregated component carriers in a band or band combination ➤Rmax : 948/1024 • For the j-th CC, Vlayers(j) is the maximum number of layers ➤Qm(j) : Maximum modulation orde…

视频推拉流/视频直播点播平台EasyDSS使用Mysql数据库接口报错502如何处理?

视频推拉流/视频直播点播EasyDSS互联网直播平台支持一站式的上传、转码、直播、回放、嵌入、分享功能&#xff0c;具有多屏播放、自由组合、接口丰富等特点。平台可以为用户提供专业、稳定的直播推流、转码、分发和播放服务&#xff0c;全面满足超低延迟、超高画质、超大并发访…

meshlab: pymeshlab合并多个物体模型并保存(flatten visible layers)

一、关于环境 请参考&#xff1a;pymeshlab遍历文件夹中模型、缩放并导出指定格式-CSDN博客 二、关于代码 本文所给出代码仅为参考&#xff0c;禁止转载和引用&#xff0c;仅供个人学习。 本文所给出的例子是https://download.csdn.net/download/weixin_42605076/89233917中的…

计算机视觉——OpenCV实现Lucas-Kanade 光流追踪

1.光流 光流法是计算机视觉中用于估计图像序列中物体运动的关键技术。它类似于观察夜空中的彗星&#xff0c;通过其在天空中的运动轨迹来追踪它的路径。在图像处理中&#xff0c;光流帮助我们理解像素点如何在连续的帧之间移动。 1.1 稀疏光流法 稀疏光流法关注于图像中的关…

tarjan学习

1.割点&#xff08;必须经过&#xff09;&#xff1a;当时&#xff0c;y是一个割点&#xff0c;x是y的一个子节点&#xff0c;当没有点x时&#xff0c;y无法访问其他点 2.割边&#xff08;必须经过&#xff09;&#xff1a;当时&#xff0c;y不经过这条边无法到达x&#xff0c…

默认成员函数:析构、深浅拷贝

析构函数 析构函数&#xff1a;与构造函数功能相反&#xff0c;析构函数不是完成对对象本身的销毁&#xff0c;局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数&#xff0c;完成对象中资源的清理工作。 特性 析构函数名时在类名前面加上字符~ class D…

Spring Bean的生命周期 五步 七步 十步 循序渐进

&#x1f468;‍&#x1f3eb; 参考视频地址 &#x1f496; 五步版 实例化 bean&#xff08;构造方法&#xff09;属性注入&#xff08;set() 方法&#xff09;初始化方法&#xff08;自定义&#xff09;使用bean销毁方法&#xff08;自定义&#xff09; &#x1f496; 七步版…

电子招标软件:招标提案请求(RFP)流程的步骤

招标提案请求&#xff08;RFP&#xff09; &#xff0c;可能不是评估专业能力和复杂解决方案的最佳方法&#xff0c;但仍然是产品或服务招标时的首选方法。 如果管理得当&#xff0c;招标采购过程将会是透明、客观和公正的。一份精心制作的 RFP 文件可以确定提交材料的质量、基…

linux的 /usr/sbin/nologin /sbin/nologin /bin/false /etc/nologin 的作用与区别

/usr/sbin/nologin /sbin/nologin /bin/false /etc/nologin 的作用与区别 /usr/sbin/nologin /sbin/nologin /bin/false 这三者的作用几乎一样&#xff0c;都是禁止用户登录。 /usr/sbin/nologin /sbin/nologin 是同一个文件&#xff0c;通过软连接指向。 当把用户的bash设置…

生态系统类型分布数据、土地利用数据、植被类型分布、自然保护区分布数据

引言 全国自然保护区生态系统类型分布信息产品是指基于Landsat TM数字影像&#xff08;以地形图纠正&#xff09;&#xff0c;采用全数字化人机交互遥感快速提取方法&#xff0c;建立全国自然保护区生态系统结构数据集&#xff0c;同时做成多种尺度的栅格数据&#xff0c;其中包…