Can `FnMut` return a mutable reference, or is there an `iter::from_fn` alternative?

I'm trying to implement a method that returns an iterator of element references and mutable references, from calculated indices. Here are some minimal examples that just return an iterator of the element at index i:

    fn iterate_index<'a, T: 'a>(&'a self, i: usize) -> impl Iterator<Item = &'a T>
    where
        Self: Index<usize, Output = T> + 'a,
    {
        iter::from_fn(move || Some(&self[i]))
    }

    fn iterate_index_mut<'a, T: 'a>(&'a mut self, i: usize) -> impl Iterator<Item = &'a mut T>
    where
        Self: IndexMut<usize, Output = T> + 'a,
    {
        iter::from_fn(move || Some(&mut self[i]))
    }

The first method which returns references passes, while the second fails with the error;

error: captured variable cannot escape `FnMut` closure body
   --> a.rs:305:31
    |
305 |         iter::from_fn(move || Some(&mut self[i]))
    |                             - ^^^^^^^^^^^^^^^^^^ returns a reference to a captured variable which escapes the closure body
    |                             |
    |                             inferred to be a `FnMut` closure
    |
    = note: `FnMut` closures only have access to their captured variables while they are executing...
    = note: ...therefore, they cannot allow references to captured variables to escape

Looking at other questions, my understanding is that iter::from_fn takes a FnMut argument, which cannot return a mutable reference. My questions are:

  1. Is that understanding correct?
  2. Is there a way I can use iter::from_fn to return mutable references?
  3. If not, are there any alternatives that can avoid creating my own struct and implementing Iterator on it for such a small case?
  4. Any other suggestions?

It's not about from_fn taking FnMut. It can return mutable references just fine. I'm not sure what the error is about, but if it wasn't there, you'd still have problems. As written, there is no way to create this iterator, since the Iterator trait requires that all items must be able to exist simultaneously. If you call next twice, you'll have two mutable references to the same item, which is not allowed. Additionally, Rust doesn't have a way to check indices for uniqueness, so even if you use a different i each time, Rust won't be able to tell that the resulting mutable references aren't the same. In general trying to create this iterator with indexing won't work.

If your type has an underlying collection like Vec or HashSet, use its iterator. This will be both simpler and more efficient than using from_fn. If not, then the proper way to implement Iterator will depend on how the data is stored.

2 Likes

Your explanation makes a lot of sense. I think an example would make it more clear why this approach is useful for me, though:

If we consider the struct to hold a Vec, and I with to implement indexing for a 2d (square) array for example, it will be easier to visualize the problem. The struct does basically mimic a 2D array, but there are patterns I wish to get mutable slices of. Let's forget alternative libraries and just consider the implementation. For the indices i and j of a square matrix where an axis has n elements, I can iterate over a row with (n * j)..(n * (j + 1)). For a column, however, I need (j * n) + i, which is not an array. For such a case, an iterator which borrows the elements at these indices would be quite useful.

To make things even more complicated, my next step was attempting to split the array so I can mutate multiple areas. For splitting a row this is, once again, quite simple. But perhaps splitting a column is too much for the moment...

The column iterator isn't too difficult since they're still in sequential order. It's just

vec.iter_mut()
    .skip((j * n) + i)
    .step(n)

Splitting by column, however, is no longer possible in safe code. You need to use raw pointers and traverse with pointer arithmetic.

Thanks for the help. Unfortuantly the iter_mut approach won't work for my particular case as patterns will not have fixed variables I can pass to the adaptors. Your explanation above did help, however, as I think I need to reconsider my approach. I'll mark this as resolved.

1 Like

Similar to how Iterator doesn't support lending iterators, the Fn(..) traits don't support closures which return borrows of themselves. The non-&mut version works because you can effectively return a copy of the capture,[1] but with &mut the notional attempted implementation is something like...

impl FnMut<()> for Closure<'cap> {
    fn call_mut<'slf>(&'slf mut self, args: ()) -> <Self as Fn<()>>::Output {
        Some(&mut self.capture[i])
        //   ^^^^^^^^^^^^^^^^^^^^ lifetime capped by 'slf
        //   (the type of this expression contains `'slf`)
    }
}

...where <Self as Fn<()>>::Output must be a single type (and types that differ by lifetime are distinct types). So just like lending iterators aren't possible with Iterator due to Item being a single type, lending closures aren't possible due to Output being a single type (a non-generic associated type).

(If lending closures were supported somehow but lending iterators still were not, there would still need to be a compilation failure for the reasons you explain.)


  1. you can get a &'long _ out of a &'short &'long _ via shared references implementing Copy ↩ī¸Ž

1 Like