【问题标题】:How can I import modules only if they exist?如何仅在模块存在时导入模块?
【发布时间】:2023-01-08 04:11:07
【问题描述】:

我正在做 advent of code,这是 25 个编程问题的集合,一个用于 advent 的每一天。

我在它自己的单独文件/模块中构建每一天,因此例如 2021 年的第 7 天将位于 src/years/year2021/day07.rs。所以 src/years/year2021/mod.rs 最终只是 pub mods

pub mod day01;
pub mod day02;
pub mod day04;
// and so on...

有没有办法动态生成这个列表(使用递归宏之类的东西),所以检查模块 day01 是否可以从这个上下文访问(或者如果 ./day01.rs 存在)并自动生成 pub mod,然后添加更多的文件被创建。

最好的是能够检查是否存在任何名称,例如模块或模块内的函数。

【问题讨论】:

标签: rust conditional-compilation


【解决方案1】:

您可以使用 build.rs 根据构建时存在的文件生成模块。

可能是这样的

let years_path = path::Path::new("./src/years");
let mut mod_file = fs::File::create(years_path.join("mod.rs")).unwrap();

let paths = fs::read_dir(years_path).unwrap();

for entry in paths {
    let entry = entry.unwrap();
    if entry.metadata().unwrap().is_dir() {
        writeln!(
            mod_file,
            "mod {};",
            entry.path().file_name().unwrap().to_str().unwrap()
        )
        .unwrap();
    }
}

【讨论】:

  • 接受了这个作为答案,但我没有在 src 目录中生成 rs 文件,而是将它们放在 OUT_DIR 中,文件名基于模块,然后在 src/ 内的 mod.rs 中,我包含!()基于 module_path!()加上一个后缀。这样这些自动生成的“标题”就不会污染 git 提交
【解决方案2】:

我使用的是 build.rs 的一个版本,与 @pidgeonhands 非常相似。 它对文件夹内的奇怪文件更有弹性(它只会在无法创建或写入文件时崩溃)并且可以工作多年:

use std::{
    error::Error,
    ffi::OsString,
    fs::{self, File},
    io::Write,
    path::Path,
};

fn main() -> Result<(), Box<dyn Error>> {
    println!("cargo:rerun-if-changed=src/years");
    let years_path = Path::new("src/years");
    let mut years_mod_file = File::create(years_path.join("mod.rs"))?;
    for year in fs::read_dir("src/years")? {
        let Ok(year) = year else {continue};
        let year_name = year.file_name();
        let Some(year_name) = year_name.to_str() else {continue};
        if year_name != OsString::from("mod.rs") {
            writeln!(years_mod_file, "pub mod {year_name};")?;
            let mut year_mod_file = File::create(year.path().join("mod.rs"))?;

            for day in fs::read_dir(year.path())? {
                let Ok(day) = day else {continue};
                if day.file_name() != OsString::from("mod.rs") {
                    let day_name = day.path();
                    let Some(day_name) = day_name.file_stem() else {continue};
                    let Some(day_name) = day_name.to_str() else {continue};
                    writeln!(year_mod_file, "pub mod {day_name};")?;
                    println!("{:?}", day_name);
                }
            }
        }
    }
    Ok(())
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-14
    • 1970-01-01
    • 1970-01-01
    • 2014-02-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多