通过rustlings源码了解rust如何从命令行参数里面获取值的方式

我不知道这篇文章的难度会如何,因为我其实和在看这篇文章的你一样,从零开始学习和了解rustlings的实现方式,通过这个方式,了解rust对main函数的传参。

第一个问题,rustlings使用了什么工具?

我首先是打开了 src 文件,找到main函数,main函数里面我们看到它在整个函数的开始创建了一个新的对象或者是变量
通过rustlings源码了解rust如何从命令行参数里面获取值的方式

从这里我们可以看到这个函数的名字是args,类型是Args,很显然这个类型不是我们已知的任何类型,那就ctrl进去先看看这个是什么

struct Args {
    /// show outputs from the test exercises
    #[argh(switch)]
    nocapture: bool,
    /// show the executable version
    #[argh(switch, short = 'v')]
    version: bool,
    #[argh(subcommand)]
    nested: Option<Subcommands>,
}

然后我发现我完全看不懂,我觉得这是个必然,那我们就只能层层解析了。对于一个奇怪的东西来说,找到这个函数里面的关键词含义至关重要,对于这个模块,最应该被注意的就是修饰整个模块的struct。我相信你和我一样完全不知道这个是个啥,所以我们一起去看一下rust的the book的中文译本:

通过rustlings源码了解rust如何从命令行参数里面获取值的方式

从图中,它描述了一个专有词,元组,我们转到元组的定义:
通过rustlings源码了解rust如何从命令行参数里面获取值的方式

从图中我们可以看到,元组是一个基于多类型数据的集合,可以通过[name].[element]获取其中的内容。struct是一种元组的升级,给每个元素定义了一个变量名,这样可以用变量名来获取想要的内容。

根据以上内容,我们知道了结构体的功能,组合一系列的变量名类型组,来表达特定的事物。所以它的参数种类就会出现三种,-nocaptureversion,以及nested这三种参数类型。

第二个问题,这三个参数是什么,它们又是具体从哪些代码实现的?

首先这些参数在启动的时候已经存在了,毕竟我们已经看到一个类型为Args的args实例(实现结构体的接下来统一称为实例),它已经被初始化了,也就是说,我们可以显式的对这些数据进行操作。

接下来我们开始试图猜测。首先在一开始,我们安装的时候,我们就能看到一个欢迎致辞在这里我们发现,有一个明确的命令 rustlings watch以及rustlings hint,这两个明显是从命令行中获取的,然而在结构体中,我们找不到这两个内容,非常非常的奇怪。

接下来我们关注一下这个实例中每个成员(变量)的类型。我们可以看到除了nested之外,nocaptureversion都是boolean这个基本类型,而另一个nested却是Option类型。

虽然我在java中接触过所谓泛型这个概念,也看过很棒的泛型的使用例子,我可以很快的判断,这里的Option<···>就是一个泛型。泛型的定义一般而言是对不同的输入类型的数据进行相同流程的处理,但是我并不清楚rust中泛型要如何处理。我唯一知道的就是如果我要在这里研究泛型,那么这篇文章就不是一篇操作和思考说明了,而是一个冗长的语法说明了。

所以我们直接去关注Option是什么,我对这个内容并不熟悉,所以我们首先判断这个东西是属于rust的基础功能还是被rustlings的开发团队新写的东西。

这里可以使用rust官方提供的cargo doc的功能,在命令行中输入cargo doc --op即可找到很多有用的东西,同时在我们自己写代码的时候,我个人也非常推荐学习rustlings的文档注释的写法,使用///来快速保存自己的文档注解,让之后的人和之后的自己看得懂自己写的是什么。

我们在文档中搜索rustlings实际使用的工具里面Option是什么如果直接搜索Optiong的话,会出现非常多的并不相关的内容,所以我们先用Args下手,
通过rustlings源码了解rust如何从命令行参数里面获取值的方式

从图中我们可以看到,Option可以点进去,我们便点进去。

通过rustlings源码了解rust如何从命令行参数里面获取值的方式

于是我们进入了rust的官方网站,注意域名的变化,本身是一个本地的地址,然后变成了网址。进去之后我们可以选择看文档,也可以去百度,都是可行的方法。

总结一下看到的内容,option是一种可以选择返回内容的工具,它可以根据不同的情况返回不同的数据类型亦或是内容。这里它提供了一个名为Subcommands的枚举类
通过rustlings源码了解rust如何从命令行参数里面获取值的方式
枚举类是一种工具,方便选中需要的内容。其实我几乎没有写过枚举类,也说不出它的实际好处,但是我看它确实被广泛而高效地使用了。从图中我们可以看到,这里显然存入了必要的指令,包括在欢迎致辞中的runhint悉数登场,以及两个我们不认识的也全都出现了。那到这里我们已经找到了全部我们能够输入的内容了吧?也许吧,一般来说在这个情况下我们可以做一个尝试,通常是有效的,在linux上使用 man rustlings或者在win上使用rustlings --help来看看它自己默认携带了哪些选项。
通过rustlings源码了解rust如何从命令行参数里面获取值的方式

没有尝试成功的一个小插曲:help命令在哪里

我们发现help选项并没有被实际写出来,其他内容都和我们找到的一模一样,那么我们就先试试看能不能找到这个help吧。很遗憾,我没有找到它,这个时候回到一开始我们创建这个args实例的地方,我们注意一下它是从什么原型里面创建的:argh::from_env();直接点进去,我们可以看到一个非常特殊的东西
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MRRDEdsi-1622127236243)(https://pic.finnewworld.top/img/2021/05/26/ewq9b4.png)]

这是一个谷歌的库,使用BSD风格,我们试试能不能找到help吧
通过rustlings源码了解rust如何从命令行参数里面获取值的方式

从这里我们可以看到help确实是从这里来的,因为它写的范例代码里面并没有写help这个选项,那么我们试图深入一下,看看是不是有办法对它进行处理,于是我们找到function:
通过rustlings源码了解rust如何从命令行参数里面获取值的方式

我们发现两个完全一样介绍的函数,并不清楚为啥不一样,也不知道为啥会有两个,但是有cargo那个肯定会涉及更多的内容,于是我打开了那个短的
通过rustlings源码了解rust如何从命令行参数里面获取值的方式

没错就是这个,它告诉我们,如果程序启动不成功或者需要help选项,它就会出来干活这很棒,也就是说,接下来我们很快就能找到这个help了。
通过rustlings源码了解rust如何从命令行参数里面获取值的方式

然后我没找到!确切的来说是它被封到了一个不是用rust写的内容中,我简述一下我经历了什么。
首先要知道clion的这个工具,如果你使用的是其他的编辑器的debug请自行查找如何命令行debug,我个人不是很会&很懂这个debug内部的流程,我也看到有大佬用命令行debug,这个仁者见仁智者见智,然后我配置的操作如下:
通过rustlings源码了解rust如何从命令行参数里面获取值的方式]

有了这个配置之后,我很粗鲁的把这段代码都打上了断点:
通过rustlings源码了解rust如何从命令行参数里面获取值的方式]

大致我们可以看到一些函数被调用,然后有一个print,print里面能够被打印的东西肯定就是我们的目标,毕竟print里面的东西就是我们看到的东西,然后我们先去查查看:
通过rustlings源码了解rust如何从命令行参数里面获取值的方式]
于是这一行的全部内容都是要么被封死根本看不到要么就是一个完全看不懂的函数。

所以我最后尝试了一件事,ctrl+shift+f,搜索一下help哪里有。然而我并没有找到。
所以help的尝试到此为止。

继续我们的参数研究

对于一个新的参数的试探,首先是从不带参数开始的,我们先不带参数走一遍:
我们会看到欢迎词。
通过rustlings源码了解rust如何从命令行参数里面获取值的方式]
总之这块代码就是如果有指令,执行指令,如果没有指令,显示欢迎词,其他的内容大致都是错误检查之类的暂时不管。
通过rustlings源码了解rust如何从命令行参数里面获取值的方式]
总而言之,这里是欢迎词所在位置。
好了那接下来我们的关注点就转向了各种各样的参数。
nocapture是用来处理一些意外情况,比如说你启动了两个rustlings啊等等,意外情况我目前不打算研究,因为和我目前的主题无关。我们直接从version开始。

通过rustlings源码了解rust如何从命令行参数里面获取值的方式]
我们可以看到version的使用方法,这是一个参数,用–来调用,这里就是一个注解

通过rustlings源码了解rust如何从命令行参数里面获取值的方式]]

所以我们把所有的数据都获取了。。。出乎意料的简单,前面所有的内容像是白干了一样==,Subcommands就是命令,switch就是注解,然后数据通过main方法直接运行。
具体main里面的运行方式我也许会再开一篇文章来整理,不过这篇就到此为止,感觉结束的莫名其妙的。

上一篇:mysql5.6升级及mysql无密码登录


下一篇:Springboot jar包部署使用Https