昨天我们学完了测试相关的
今天继续往下
I/O
项目:构建一个命令行程序我们来写一个命令行程序,验收下之前学的内容。
要做一个搜索工具类似grep
(globally search aregularexpression andprint
)。
相信大家都或多或少接触过linux
服务器,查日志的时候用这个grep
再好不过了。
它接收两个参数,一个是需要匹配的字符串,另一个是文件路径。
然后输出匹配的信息。
我们的程序将涉及到以下几个之前学过的概念:
我们来创建一个binary
项目,就叫minigrep
。
我们之前有用到过,在实现一个猜数游戏的时候,从命令行获取用户输入的数字。
然而这玩意儿只能接受一个参数,不过如果分两次输入也不是不行。
但是没必要,rust
的标准库中有比这更好康的:std::env::args
。
这个args
的function
返回的是一个迭代器iterator
,这个我们暂时还没学到。
目前关于迭代器我们只需要知道两点:
collect
的方法可以把这个迭代器转化成一个集合。这里有一点需要注意,那就是args
这个返回的内容并不一定是有效的,而当他输入的是违法的字符时,整个程序就会直接panic
。
不过这个问题也是可以避免的,可以使用std::env::args_os
,他可以接收非法字符,它返回的迭代器中的值的类型是OsString
而非args
的string
。
不过我们这里不用它,因为没这个需求。我们只是做一个简单的demo
。而且args_os
的值会因为平台的不同而不同。
另外有一点你应该注意到了,那就是我们手动声明了args
这个集合的类型,这是因为rust
并不能推断出你想要的集合的类型。
既然能获得数据了,那么我们就得有个变量来存储它们。
我们可以声明两个变量或者用元组,但这都不是最好的方案。
没错,相信你已经想到了,那就是struct
。
这里有个点就是我用了&String.clone()
这个方法,直接copy
了一份堆内存也就是深复制。
为什么这么做而不是用生命周期呢?
因为这样写的代码用不了生命周期,new
方法中的args
在new
被调用完之后就已经失效了,而这个时候我们引用的数据随着struct
还在main
函数中,这个时候引用指向的地址就已经有数据问题了。
这个代码其实也能改成使用生命周期的方式
俩种都可以,看你自己。一方面是性能问题,一方面代码维护问题。
我个人更倾向于第一种写法,不过args
获取应该放到main
函数里,这样方便阅读。
现在我们的就能获取和保存这些数据了,接下来我们要实现查询了。
我们直接创建一个文件poem.txt
然后复制以下内容到文件里
接下来我们就可以调用读取的api
了。
我们之前其实也用过读取文件的方法,File::open
成功获取到了。
但是上面的代码有些冗杂,还记得我们在学可恢复错误的?
操作符的时候最后用的一个方法吗?
直接fs::read_to_string()
简洁明了。
这样我们的文件内容就获取成功了。
接下来该轮到匹配了。
poem
变量目前是一个String
,所以对于字符串来说,我们可以用split("\n")
将它们切割成一行一行的。
其中contains
可以传入一个闭包,或者&str
或者char
。
当然,我们可以用lines
替代split("\n")
实际上他俩差不多。
ok
,这样我们就匹配完了,并且也最终输出到终端。
今天我们一步一步的实现了这个minigrep
,但是它还有挺多问题,比如现在的代码全部都堆在main.rs
中,这是不优雅的,另外我们也应该引入测试,这样可以提高代码的可维护性。
还有我们目前对错误的处理都是直接expect
,这样不太友好。
明天我们来优化下代码组织,然后加上驱动测试以及对错误的处理。
发布于 2022-12-22 21:11・IP 属地广东