Estou tentando usar crate docx_rust
para mesclar uma lista de documentos do Word em um. Eu tento isso, mas estou tendo um problema de vida doc
porque ele é descartado no final do for
loop.
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(())
}
Tentei empurrar cada documento aberto para um vetor, mas isso não estende o tempo de vida. Tentei armazená-los em um Rc::new()
, mas não funcionou.
Aceitarei qualquer solução!
Eu tentei executar o código acima na minha máquina local. O que funcionou para mim foi
Como pode ser visto, as diferenças são:
Há 2 loops em vez de 1.
A vida útil do Docx foi estendida carregando-o primeiro em um vetor
Em seguida, tomamos uma referência sobre cada elemento do vetor.
E então realizamos a operação de análise e extensão
Isso garante que o vetor de documentos seja responsável por manter o tempo de vida do DocxFile, aparentemente estendendo o tempo de vida
Agora, quando pegamos uma referência do DocxFile em p_doc/o 2º loop, a variável da qual estamos pegando uma referência não vai se mover.
Um motivo para os problemas é que p_doc pega uma referência para doc :
Então, com o código original, sempre que chegamos ao fim do bloco, o tempo de vida do doc termina, mas merged_doc via extend ainda mantém as referências ao doc original.
Então, devido a problemas de tempo de vida, o código acima não funcionará. O que significa que teríamos que estender o tempo de vida.
Se você tentar enviar para um vec para estender o tempo de vida, o Rust reclama porque merged_doc via p_doc ainda está segurando uma referência para doc, então o verificador de empréstimo sente que devido a uma movimentação, esse link de referência pode ser invalidado. Então essa abordagem também não funciona.
É por isso que a abordagem de 2 loops funciona. Como estamos primeiro inserindo no vec e somente depois pegando referências, garantindo assim que nenhuma referência possa ser invalidada.
Para mais detalhes, consulte https://doc.rust-lang.org/error_codes/E0505.html
Nossa solução usa Try para evitar mover a variável.
PS O verificador de empréstimos também reclamará da abordagem vetorial se tentarmos, por exemplo, enviar para o vetor após o loop com os empréstimos.
Vamos dar uma olhada neste exemplo simples