编写打印任务的函数

已完成

我们需要定义的第三个也是最后一个操作是 list_tasks 函数。 此函数只需读取日志文件并打印任务列表(如果有):

pub fn list_tasks(journal_path: PathBuf) -> Result<()> {
    // Open the file.
    let file = OpenOptions::new().read(true).open(journal_path)?;
    // Parse the file and collect the tasks.
    let tasks = collect_tasks(&file)?;

    // Enumerate and display tasks, if any.
    if tasks.is_empty() {
        println!("Task list is empty!");
    } else {
        let mut order: u32 = 1;
        for task in tasks {
            println!("{}: {}", order, task);
            order += 1;
        }
    }

    Ok(())
}

此函数比同级函数稍微简单一些,因为它不需要写入文件。 我们再次重用了 collect_tasks helper 函数,这也证明了重构很有用。 然后,在尝试列出任务向量的内容之前,我们检查其是否为空。

打印列表时,我们使用一个从 1 开始的简单计数器来枚举任务。 这个数字与用户传递给 complete_task 操作的数字相同。

请注意,此代码将不会编译,因为 Task 结构尚未实现 Display 特征。 正如我们在其他模块中看到的那样,Display 特征用于向最终用户显示结构表示形式,这正是我们在此要执行的操作。

为类型实现 Display 特征非常简单。 我们只需实现 fmt 函数,如下所示:

use std::fmt;

impl fmt::Display for Task {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let created_at = self.created_at.with_timezone(&Local).format("%F %H:%M");
        write!(f, "{:<50} [{}]", self.text, created_at)
    }
}

Display::fmt 函数中,我们将 DateTime<Utc> 时间戳转换为 DateTime<Local> 结构,这样用户就可以查看以本地时间创建任务的日期和时间。

你可能想知道为什么我们一开始没有使用 DateTime<Local> 类型来定义 created_at 字段。 我们没有这样做是因为 chrono::serde::ts_seconds 模块需要在 Utc 类型上特殊化 DateTime 结构。

然后,使用 write! 宏将 Task 表示形式写入 Formatterf。 我们按如下所示表示 Task 类型:

  • {:<50}:填充了 50 个空格的左对齐字符串。
  • 后跟 [{}]:创建任务的日期和时间,并用括号括起。

总结

以上就是我们关于 tasks.rs 模块文件的探索。 如果你想要查看任务模块的完整代码,请在 Rust Playground 中进行查看。 我们应该执行的最后一步是将 cli::CommandLineArgs 捕获的用户输入与此模块中定义的三个函数绑定。

在下一节中,我们将连接 main.rs 文件中的这些端点并完成我们的应用程序。