二进制程序关注点分离的指导性原则

  • 将程序拆分为 main.rs 和 lib.rs,将业务逻辑放入 lib.rs
  • 当命令行解析逻辑较少时,将它放在 main.rs 也行
  • 当命令行逻辑边复杂时,需要将它从 main.rs 提取到 lib.rs

    经过上述拆分,留在 main 的功能有:

  • 使用参数值调用命令行解析逻辑

  • 进行其他配置
  • 调用 lib.rs 中的 run 函数
  • 处理 run 函数可能出现的错误

    改进模块化

    ```rust use std::env; use std::fs;

fn main() { let args: Vec = env::args().collect();

  1. let config = Config::new(&args);
  2. let contents =
  3. fs::read_to_string(config.filename).expect("Something went wrong reading the file");
  4. println!("With text:\n{}", contents);

}

struct Config { query: String, filename: String, }

impl Config { fn new(args: &[String]) -> Config { let query = args[1].clone(); let filename = args[2].clone(); Config { query, filename } } }

  1. <a name="SRH3F"></a>
  2. ## 错误处理
  3. ```rust
  4. use std::env;
  5. use std::fs;
  6. use std::process;
  7. fn main() {
  8. let args: Vec<String> = env::args().collect();
  9. let config = Config::new(&args).unwrap_or_else(|err| {
  10. println!("Problem parsing arguments: {}", err);
  11. process::exit(1);
  12. });
  13. let contents =
  14. fs::read_to_string(config.filename).expect("Something went wrong reading the file");
  15. println!("With text:\n{}", contents);
  16. }
  17. struct Config {
  18. query: String,
  19. filename: String,
  20. }
  21. impl Config {
  22. fn new(args: &[String]) -> Result<Config, &'static str> {
  23. if args.len() < 3 {
  24. return Err("not enough arguments");
  25. }
  26. let query = args[1].clone();
  27. let filename = args[2].clone();
  28. Ok(Config { query, filename })
  29. }
  30. }

优化

  1. use std::env;
  2. use std::error::Error;
  3. use std::fs;
  4. use std::process;
  5. fn main() {
  6. let args: Vec<String> = env::args().collect();
  7. let config = Config::new(&args).unwrap_or_else(|err| {
  8. println!("Problem parsing arguments: {}", err);
  9. process::exit(1);
  10. });
  11. if let Err(e) = run(config) {
  12. println!("Application error: {}", e);
  13. process::exit(1);
  14. }
  15. }
  16. fn run(config: Config) -> Result<(), Box<dyn Error>> {
  17. let contents = fs::read_to_string(config.filename)?;
  18. println!("With text:\n{}", contents);
  19. Ok(())
  20. }
  21. struct Config {
  22. query: String,
  23. filename: String,
  24. }
  25. impl Config {
  26. fn new(args: &[String]) -> Result<Config, &'static str> {
  27. if args.len() < 3 {
  28. return Err("not enough arguments");
  29. }
  30. let query = args[1].clone();
  31. let filename = args[2].clone();
  32. Ok(Config { query, filename })
  33. }
  34. }

拆分

  1. // main.rs
  2. use minigrep::Config;
  3. use std::env;
  4. use std::process;
  5. fn main() {
  6. let args: Vec<String> = env::args().collect();
  7. let config = Config::new(&args).unwrap_or_else(|err| {
  8. println!("Problem parsing arguments: {}", err);
  9. process::exit(1);
  10. });
  11. if let Err(e) = minigrep::run(config) {
  12. println!("Application error: {}", e);
  13. process::exit(1);
  14. }
  15. }
  1. // lib.rs
  2. use std::error::Error;
  3. use std::fs;
  4. pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
  5. let contents = fs::read_to_string(config.filename)?;
  6. println!("With text:\n{}", contents);
  7. Ok(())
  8. }
  9. pub struct Config {
  10. pub query: String,
  11. pub filename: String,
  12. }
  13. impl Config {
  14. pub fn new(args: &[String]) -> Result<Config, &'static str> {
  15. if args.len() < 3 {
  16. return Err("not enough arguments");
  17. }
  18. let query = args[1].clone();
  19. let filename = args[2].clone();
  20. Ok(Config { query, filename })
  21. }
  22. }