我正在尝试使用 cratedocx_rust
将 Word 文档列表合并为一个。我尝试了这个,但我遇到了一个问题,doc
因为它在循环结束时被丢弃了for
。
use docx_rust::{Docx, DocxFile};
fn merge_docs<'a>(file_paths: &[&str], output_path: &str) -> Result<(), Box<dyn std::error::Error>> {
let mut merged_doc = Docx::default();
for path in file_paths {
let doc = DocxFile::from_file(Path::new(path))?; // No Rc here initially
let mut p_doc = doc.parse().unwrap();
merged_doc.document.body.content.extend(p_doc.document.body.content.drain(..));
}
merged_doc.write_file(Path::new(output_path))?;
Ok(())
}
我尝试将每个打开的文档推送到一个向量中,但这并不能延长生命周期。我尝试将它们存储到一个中Rc::new()
,但没有成功。
我会欢迎任何解决方案!
我尝试在本地机器上运行上述代码。对我有用的是
可以看出,差异在于:
有 2 个循环,而不是 1 个。
通过首先将 Docx 全部加载到向量中,可以延长其生命周期
然后我们对向量的每个元素进行引用。
然后执行解析和扩展操作
这确保了 docs 向量负责维护 DocxFile 的生命周期,从而延长了生命周期
现在,当我们在 p_doc/第二个循环中引用 DocxFile 时,我们引用的变量不会移动。
出现问题的原因是 p_doc引用了 doc:
因此,使用原始代码时,当我们到达块的末尾时,doc 的生命周期就结束了,但是通过扩展的 merged_doc 仍然保留对原始文档的引用。
因此,由于生命周期问题,上述代码将无法工作。这意味着我们必须延长生命周期。
如果您尝试推送到 vec 以延长生命周期,Rust 会抱怨,因为通过 p_doc 的 merged_doc 仍然持有对 doc 的引用,因此借用检查器会认为由于移动,该引用链接可能会失效。所以这种方法也行不通。
这就是 2 循环方法有效的原因。因为我们首先插入 vec,然后才获取引用,从而确保不会使任何引用失效。
有关更多详细信息,请查看https://doc.rust-lang.org/error_codes/E0505.html
我们的解决方案使用尝试避免移动变量。
PS 如果我们尝试在借用循环之后将其推送到向量,借用检查器也会抱怨向量方法。
让我们看看这个简单的例子