rust例子grep、闭包、迭代器
简单的grep demo
接收命令行参数
use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
let query = &args[1];
let filename = &args[2];
println!("search for: {}",query);
println!("in file: {}",filename);
}
// > cargo run 123 456
// Finished dev [unoptimized + debuginfo] target(s) in 0.01s
// Running `target\debug\mingrep.exe 123 456`
// query: 123
// filename: 456
读取文件
let contents = fs::read_to_string(filename)
.expect("Something went wrong reading the file.");
println!("content: {}",contents);
重构

// 改善模块化和错误处理
use std::{env, fs, process};
fn main() {
let args: Vec<String> = env::args().collect();
let config = Config::new(&args).unwrap_or_else(|err| {
println!("Problem parsing arguments: {}",err);
process::exit(1);
});
println!("search for: {}",config.query);
println!("in file: {}",config.filename);
let contents = fs::read_to_string(config.filename)
.expect("Something went wrong reading the file.");
println!("content: {}",contents);
}
// lib.rs
struct Config {
query: String,
filename: String,
}
impl Config {
fn new(args: &[String]) -> Result<Config, &'static str> {
if args.len() < 3 {
return Err("not enough arguments.")
}
let query = args[1].clone();
let filename = args[2].clone();
Ok(Config {
query,
filename,
})
}
}
TDD测试驱动开发
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
let mut results = Vec::new();
for line in contents.lines() {
if line.contains(query) {
results.push(line);
}
}
results
}
# [cfg(test)]
mod tests {
use super::*;
#[test]
fn one_result() {
let query = "duct";
let contents = "\
Rust:
Safe, fase, productive.
Pick three.";
assert_eq!(vec!["Safe, fase, productive."], search(query,contents));
}
}
然后将可运行的search
函数代码加入原有代码中。
pub fn run(config: Config) -> Result<(), Box<dyn Error>>{
println!("search for: {} in file: {}\n\n", config.query,config.filename);
let contents = fs::read_to_string(config.filename)?;
for line in search(&config.query, &contents) {
println!("{}", line);
}
Ok(())
}
使用环境变量
let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
将错误信息输出到标准错误
// 标准输出:stdout
println!
// 标准错误:stderr
eprintln!
闭包
closure
可以捕获其所在环境的匿名函数。
类型推断
闭包不要求标注参数和返回值的类型。通常短小,只在狭小的上下文中工作,编译器通常能推断出其类型,也可以手动标注。
闭包的定义最终只会为参数和范沪指推断出唯一具体的类型。
存储闭包
- 创建一个struct,持有闭包及其调用结果。
每个闭包实例有自己的唯一匿名类型。
struct Cacher<T>
where
T: Fn(u32) -> u32
{
calculation: T,
value: Option<u32>,
}
impl<T> Cacher<T>
where
T: Fn(u32) -> u32
{
fn new(calculation: T) -> Cacher<T> {
Cacher { calculation, value: None, }
}
fn value(&mut self, arg: u32) -> u32 {
match self.value {
Some(v) => v,
None => {
let v = (self.calculation)(arg);
self.value = Some(v);
v
}
}
}
}
fn work(intensity: u32, number: u32) {
let mut exp_closure = Cacher::new(|num| {
println!("calculating slowly...");
thread::sleep(Duration::from_secs(2));
num
});
if intensity < 25 {
println!("haha {}",exp_closure.value(intensity));
println!("hengheng {}",exp_closure.value(intensity));
} else {
}
}
闭包捕获上下文
let x = 4;
let eqx = |z| z==x;
let y = 4;
assert!(eqx(y));

在参数列表前使用move
关键字,可以强制闭包取得环境值的所有权。
迭代器
迭代器模式:对一系列项执行某些任务。
#[test]
fn iterator_sum() {
let v1 = vec![1,2,3];
let v1_iter = v1.iter();
let total:i32 = v1_iter.sum();
assert_eq!(total,6);
}
map操作:
#[test]
fn iterator_sum() {
let v1 = vec![1,2,3];
let v2: Vec<_> = v1.iter().map(|x| x+1).collect();
assert_eq!(v2,vec![2,3,4]);
}
闭包捕获环境:
let tt = 2;
let v3: Vec<_> = v1.into_iter().filter(|x| x%tt==1).collect();
自定义迭代器:
- 实现next方法
将输入以迭代器方式传递:
pub fn new(mut args: std::env::Args) -> Result<Config, &'static str> {
if args.len() < 3 {
return Err("not enough arguments.")
}
args.next();
let query = match args.next() {
Some(arg) => arg,
None => return Err("Didn't get a query string"),
};
let filename = match args.next() {
Some(arg) => arg,
None => return Err("Didn't get a filename")
};
let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
Ok(Config {
query,
filename,
case_sensitive,
})
}