Open DCNick3 opened 11 months ago
I haven't been using GATs very long, so I don't know if there are any workarounds for stable, but I does seem that this example does actually compile with RUSTFLAGS="-Zpolonius" cargo +nightly build
@DCNick3 This article should explain why your example doesn't compile. There might be a way to make it work for your specific use case (want to share a more specific example?), but if not I would recommend checking out lender - it has some tricks to get around this borrow checker limitation. Also, here's a slightly more simplified version of your example:
use gat_lending_iterator::LendingIterator;
struct It<'root> {
unit: &'root (),
}
impl<'root> LendingIterator for It<'root> {
type Item<'a> = &'a ()
where Self: 'a;
fn next(&mut self) -> Option<Self::Item<'_>> {
Some(self.unit)
}
}
fn usage<'a>(unit: &'a ()) {
// this fails to compile
It { unit }.map(|_| {});
// this compiles
let mut iter = It::<'a> { unit };
while let Some(item) = iter.next() {
(|_| {})(item);
}
}
fn main() {
usage(&())
}
BTW it's good to know polonius solves this! Makes me optimistic about the future of this crate.
Thanks for the article!
I think my "concrete" example is a bit too domain-specific and just has too much stuff to actually be useful for understanding the problem that I have. But in its core I just want to return a pair: an item lended from an iterator (it only exists for one iteration, to re-use the same memory for it) and an item that is borrowed from the environment.
I ended up changing the design to use a less flexible interface: visitors, so now not the code that produces the items has to be implemented as a state machine, but the code that uses them. It's a bit more verbose than I would like, but it seems to work for me. If you are curious, here's what I came up with. Notice the re-use of path_buf
to construct the file path during the iteration and the fact that all directories are bound to the lifetime of 'bump
allocator (or maybe it doesn't matter here?). Unfortunately, I didn't save my attempt to make it work with the lending iterators
I have a use-case where I want to yield a tuple of two items: an idem lended from the iterator and an item borrowed from outside scope (
LendedItem
andBorrowedItem
respectively). Here's a silly example demonstrating the shape of the iterator I want, without any actual logic:Then there's a function I want to call on each element:
If I call it with
while let Some(...) = iter.next()
it compiles just fine:However, when I try to use it with
.map
, rustc complains that'root
must actually be'static
The compile time error:
The error message suggests a limitation in the borrow checker. It this true? Does this mean that there's no way to have an iterator return an item that is simultaneously lended and borrowed from the outer scope? Maybe you know of any workarounds?
full example code to copy into an IDE
```rust use std::marker::PhantomData; use gat_lending_iterator::LendingIterator; struct BorrowedItem<'root> { _marker: PhantomData<&'root ()>, } struct LendedItem<'a> { _marker: PhantomData<&'a ()>, } struct Iterator<'root> { _marker: PhantomData<&'root ()>, } impl<'root> LendingIterator for Iterator<'root> { type Item<'a> = (LendedItem<'a>, BorrowedItem<'root>) where Self: 'a; // the problem? fn next(&mut self) -> Option