Compiling playground v0.0.1 (/playground)
error[E0700]: hidden type for `impl Iterator<Item = &'s mut T>` captures lifetime that does not appear in bounds
--> src/lib.rs:35:9
|
28 | impl<'a, T> ArrayVector<'a, T> {
| -- hidden type `FlatMap<std::slice::IterMut<'s, Vector<'a, T>>, impl Iterator<Item = &'s mut T>, {closure@src/lib.rs:35:40: 35:47}>` captures the lifetime `'a` as defined here
...
34 | fn iter_mut<'s>(&'s mut self) -> impl Iterator<Item = &'s mut T> {
| ------------------------------- opaque type defined here
35 | self.array.iter_mut().flat_map(|inner| inner.iter_mut())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
For more information about this error, try `rustc --explain E0700`.
error: could not compile `playground` (lib) due to 1 previous error
As of right now, you don't avoid it. The captures trick is "the correct way to express the capture of lifetime parameters in Rust 2021" according the RFC for the new capturing rules of RPITs in the 2024 edition (which will be retrofitted to previous editions if I understand the RFC correctly). The alternative outlives trick doesn't apply to your solution as your iterator can't live for 'a (only if 's would be equal to 'a which is an antipattern described in your other question).
Thanks! What does it mean that this code compiles?
fn iter_mut<'s>(&'s mut self) -> impl Iterator<Item = &'s mut T> {
// If we can generate the corresponding unpack according to N, we can do this
return if let [i1, i2] = &mut self.array[..] {
i1.iter_mut().chain(i2.iter_mut())
} else {
panic!("Invalid Array Length")
}
}
The opaque type your return in your second snippet (Chain) doesn't capture 'a, unlike FlatMap does in the snippet of your original post. The former captures two opaque types without the 'a (returned from the Vector::iter_mut method) whereas the latter captures the Vector<'a>'s contained in the ArrayVector::array field.
Ahhhh, I'm lost. I didn't notice that Chain doesn't capture the lifetime 'a of both iters after unpacking. I don't think I want to use a outlives trick here, which, while it lets me compile, sometimes makes it useless to the caller. For now, until there's a nice rusty way to do it, I'm thinking starting with unpack might be the right path?
Sorry, I'm not saying there's anything wrong with the capture trick, but the code might look like this. If an trait is provided to the caller, the caller will be surprised by the appearance of the Captures opaque type. But we don't want to capture its relationship, nor do we want it to be passed indirectly to any external wrapper.
I don't think that Captures<'a> is a surprising bound on the RPIT on methods for Something<'a>. Note that Captures<'a> doesn't propagate or infect any other APIs, it will only be on the RPIT (Edit: and consecutive RPITs that return it). But if your problem allows avoiding the need for capturing 'a in the first place by using a different concrete return type that doesn't capture 'a, that's fine of course.
Thank you for your quick response, I agree with all of the above. Sorry for my behavior, which looks like babysteps. But I can't compile this code: Playground
Right, I amended my answer and added that the Captures<'a> would infect other RPITs. But your user can pass it around as anything that implements just Iterator<Item=&mut T>. I.e. this works fine:
fn foo<'a>(x: impl Iterator<Item = &'a mut u32>) {
for i in x {
println!("{i}");
}
}
fn main() {
let mut arr = ArrayVector {
array: [Vector::Owned(vec![0, 1]), Vector::Owned(vec![2, 3])],
};
foo(arr.iter_mut_2());
}
You do need Captures in the ≤2021 editions, but if it's the æsthetics which worry you, you can make it prettier by hiding Captures inside your own Iterator: