In my mind this should work. buf_reader contains a reference to a ZipFile tied to the lifetime of Item. In newzip_file is borrowed from zip_archive and the compiler states that zip_archive is dropped at the end of new, but how can I tell the compiler that Item will own zip_archive meaning that the reference to zip_file will be alive for the same scope (as it's tied to the lifetime of Item)?
That is, your new function is saying that the item must not outlive the filename you've given it. If you want an Item that owns its ZipFile, you need to construct an Item<'static>, or an item that is not borrowing anything.
Another problem you probably have is that your ZipFile appears to borrow from the ZipArchive, which means Item is a self-borrowing struct, and that's not allowed in safe Rust. (If Item is moved, your buf_reader could become invalid.)
An Item<'a> is necesarrily only valid within the scope of some object with lifetime 'a that it borrows from. If you're borrowing from a ZipArchive, you need to pass a reference to the ZipArchive into Item::new when you construct the item.
Thanks very much. I thought that the reference to filename might have been an issue and I refactored it to take a owned string at one point but couldn't get it to compile.
I think this is the issue, a self borrowing struct. I guess I will need change it so that I'm holding a reference to a ZipArchive.
But how can this be explained? Don't structs own their fields? If structs do own the fields, then the newly formed struct Item should have the ownership of the zip_archive field and the zip_archive variable declared in new function should no longer be the owner and the value shouldn't be dropped.
Pin doesn't magically solve the problem. You still need unsafe code to create a self-borrowing struct, Pin just makes it easier to encapsulate the unsafe code.
The real issue is that ZipFile borrows from ZipArchive, and moving the local variable into a returned struct is a move of that ZipArchive, which is not allowed while ZipFile borrows from it.
This is not quite correct: an elided lifetime will not unify with a named lifetime from an outer scope (see the next post by Yandros). The actual unelided version of new is
which means the 'a actually comes from nowhere; the caller may choose any lifetime it pleases, even 'static. The only way to satisfy that constraint inside new is to return an Item<'static>.
In this case it doesn't make a huge difference to the implementor of new because 'a and 'b are both chosen by the caller, and equally unsatisfiable.
So, if I have a ZipArchive with a single ZipFile in it is it even possible to create a struct that iterates over the ZipFile? This is basically what I would like to do, maybe I am approaching the problem in the wrong way.