rust-lang / rust-lang/libs-team
Create iterator function in std libs: split_item_mut()
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 178
- Forks
- 28
- Avg merge
- 15m
- Merged PRs (30d)
- 1
Description
Proposal
Problem statement
If I want to use a mutable vector to iterate over the same vector. I can't do this without the borrow checker starts to complain about the vector already being borrowed. There is no user friendly alternative / ergonomic solution for this problem. A possible problem:
Motivating examples or use cases
for particle in particles.iter_mut() {
for other in particles.iter_mut() {
if particle != other {
particle.velocity += other.calculate_gravity(&particle);
}
}
}
This is something the borrow checker won't allow. Of course there are options to fix this like updating the index in the vector immediately or using something like swap_remove, both solutions are not very ergonomic / user friendly in my opinion.
Solution sketch
A possible solution is:
pub trait Splitting<T> {
fn split_item_mut(&mut self, idx: usize) -> (&mut[T], &mut T, &mut [T]);
}
impl<T> Splitting<T> for Vec<T> {
fn split_item_mut(&mut self, idx: usize) -> (&mut T, OtherIterMut<T>) {
assert!(idx < self.len());
let (head, rest) = self.split_at_mut(idx);
let (item, tail) = rest.split_first_mut().unwrap();
(head, item, tail)
}
}
And to use it:
let (head, item, tail) = some_vector.split_item_mut(some_index);
// Or chain...
for other in head.iter_mut() {
other.some_field = item.some_field;
}
for other in tail.iter_mut() {
other.some_field = item.some_field;
}
Of course this isn't a boundry safe API so you can think of returning the "item" in the tuple as an Option.
Alternatives
pub type OtherIterMut<'a, T> = std::iter::Chain<IterMut<'a, T>, IterMut<'a, T>>;
pub trait Splitting<T> {
fn split_item_mut(&mut self, idx: usize) -> (&mut T, OtherIterMut<T>);
}
impl<T> Splitting<T> for Vec<T> {
fn split_item_mut(&mut self, idx: usize) -> (&mut T, OtherIterMut<T>) {
assert!(idx < self.len());
let (head, rest) = self.split_at_mut(idx);
let (item, tail) = rest.split_first_mut().unwrap();
let others = head.iter_mut().chain(tail.iter_mut());
(item, others)
}
}
And to use it:
let (item, others) = some_vector.split_item_mut(some_index);
for other in others {
other.some_field = item.some_field;
}
Links and related work
Also posted on: https://internals.rust-lang.org/t/create-iterator-function-in-std-libs-split-item-mut/19880
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading the proposal and its linked Rust Internals discussion, then compare the split_at_mut, split_first_mut, and iter_mut usage shown in the examples. No implementation file or test is named; done would require settling the API shape and documenting the accepted behavior before implementation and validation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100