Rust 如何使用include_str!对于多个文件还是整个目录?

Rust 如何使用include_str!对于多个文件还是整个目录?,rust,Rust,我想将整个目录复制到用户的$HOME中的某个位置。将文件单独复制到该目录非常简单: let contents = include_str!("resources/profiles/default.json"); let fpath = dpath.join(&fname); fs::write(fpath, contents).expect(&format!("failed to create profile: {}", n)); 我还没有找到一种方法来适应多个文件: for

我想将整个目录复制到用户的
$HOME
中的某个位置。将文件单独复制到该目录非常简单:

let contents = include_str!("resources/profiles/default.json");
let fpath = dpath.join(&fname);
fs::write(fpath, contents).expect(&format!("failed to create profile: {}", n));
我还没有找到一种方法来适应多个文件:

for n in ["default"] {
    let fname = format!("{}{}", n, ".json");
    let x = format!("resources/profiles/{}", fname).as_str();
    let contents = include_str!(x);
    let fpath = dpath.join(&fname);
    fs::write(fpath, contents).expect(&format!("failed to create profile: {}", n));
}
…编译器抱怨
x
必须是字符串文本

据我所知,有两种选择:

  • 编写自定义宏
  • 为我要复制的每个文件复制第一个代码
  • 这样做的最佳方式是什么?

    我将创建一个循环遍历目录的元组,构建一个包含名称的元组数组和另一个包含原始数据的宏调用:

    use std::{
        env,
        error::Error,
        fs::{self, File},
        io::Write,
        path::Path,
    };
    
    const SOURCE_DIR: &str = "some/path/to/include";
    
    fn main() -> Result<(), Box<dyn Error>> {
        let out_dir = env::var("OUT_DIR")?;
        let dest_path = Path::new(&out_dir).join("all_the_files.rs");
        let mut all_the_files = File::create(&dest_path)?;
    
        writeln!(&mut all_the_files, r##"["##,)?;
    
        for f in fs::read_dir(SOURCE_DIR)? {
            let f = f?;
    
            if !f.file_type()?.is_file() {
                continue;
            }
    
            writeln!(
                &mut all_the_files,
                r##"("{name}", include_bytes!(r#"{name}"#)),"##,
                name = f.path().display(),
            )?;
        }
    
        writeln!(&mut all_the_files, r##"]"##,)?;
    
        Ok(())
    }
    
    另见:

    使用宏:

    macro_rules! incl_profiles {
        ( $( $x:expr ),* ) => {
            {
                let mut profs = Vec::new();
                $(
                    profs.push(($x, include_str!(concat!("resources/profiles/", $x, ".json"))));
                )*
    
                profs
            }
        };
    }
    

    让prof_tups:Vec=incl_profile!(“默认”、“python”);
    对于prof_tups中的(prof_name,prof_str){
    设fname=format!(“{}{}”,prof_name,“.json”);
    让fpath=dpath.join(&fname);
    fs::write(fpath,prof_str).expect(&format!(&failed to create profile:{},prof_name));
    }
    
    注意:这不是动态的。这些文件(“default”和“python”)是在对宏的调用中指定的


    更新:使用
    Vec
    而不是
    HashMap

    如果您只想进行迭代,那么使用
    HashMap
    是不必要的开销。@Shepmaster正在使用它,所以我不需要另一行
    “default”
    “python”
    。。。我想我可以使用一个数组,然后将其拆分,但这似乎更简单。你会推荐什么?如我的答案所示的元组数组(
    [(名称,值)]
    )。嗨,我不知道这是否仍然是首选的方法,但是当我尝试这个方法时(在
    {projectRoot}/build.rs
    中的第一个片段,在
    {projectRoot}/src/main.rs
    中的第二个片段抱怨它找不到文件。我猜如果
    constsource\u DIR:&str=“some/path/to/include”
    是一个绝对路径,它可以工作,但是使用绝对路径对于分发来说并不好。我还遗漏了什么吗?@DavSanchez确实向您展示了如何将
    SOURCE\u DIR
    替换为与您的项目相关的内容?是的,我尝试过,它通过删除
    也起到了作用来自上次写入时的原始字符串
    n!()
    build.rs
    。谢谢!
    macro_rules! incl_profiles {
        ( $( $x:expr ),* ) => {
            {
                let mut profs = Vec::new();
                $(
                    profs.push(($x, include_str!(concat!("resources/profiles/", $x, ".json"))));
                )*
    
                profs
            }
        };
    }
    
    let prof_tups: Vec<(&str, &str)> = incl_profiles!("default", "python");
    
    for (prof_name, prof_str) in prof_tups {
        let fname = format!("{}{}", prof_name, ".json");
        let fpath = dpath.join(&fname);
        fs::write(fpath, prof_str).expect(&format!("failed to create profile: {}", prof_name));
    }