rustdocxlifetime

Why I can't extend the lifetime of the variable of my function?


I am trying to use crate docx_rust to merge a list of Word documents into one. I try this but I am having a lifetime problem with doc because it's dropped at the end of the 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(())
}

I tried to push each doc opened into a vector, but it does not extend the lifetime. I tried to store them into a Rc::new(), but it did not work.

I will welcome any solution!


Solution

  • I tried running the above code on my local machine. What worked for me was

    use docx_rust::{Docx, DocxFile};
    use std::path::Path;
    
    fn merge_docs<'a>(file_paths: &[&str], output_path: &str) -> Result<(), Box<dyn std::error::Error>> {
        let mut merged_doc = Docx::default();
        let mut docs: Vec<DocxFile> = Vec::new();
    
        for path in file_paths {
            let doc = DocxFile::from_file(Path::new(path))?;  // No Rc here initially
            docs.push(doc);
        }
        for doc in &docs{
            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(())
    }
    

    As can be seen, the differences are:

    For further details, check https://doc.rust-lang.org/error_codes/E0505.html

    Here, the function eat takes ownership of x. However, x cannot be moved because the borrow to _ref_to_val needs to last till the function borrow. To fix that you can do a few different things:
    Try to avoid moving the variable.
    Release borrow before move.
    Implement the Copy trait on the type.

    Our solution uses Try to avoid moving the variable.

    P.S. The borrow checker will also complain the vector approach if we attempt to let's say push to the vector after the loop with the borrows.

    Lets look at this simple example

    for path in file_paths {
        let doc = DocxFile::from_file(Path::new(path))?;  // No Rc here initially
        docs.push(doc);
    }
    for doc in &docs{
        let mut p_doc = doc.parse()?;
        merged_doc.document.body.content.extend(p_doc.document.body.content.drain(..));
    }
    {
        let doc = DocxFile::from_file("origin.docx").unwrap();
        docs.push(doc);
    }