Vector iterate and update

hi,
I am a new beginner in Rust. I have a list of structs in a vector, which I am trying to iterate, filter and update matching values.
From docs, my understanding is that when we iterate and filter a vector, the result is a new/copy of the vector, not the original one.
How to approach this, the option I see while searching online is to use afor loop with an index.
for i in 0...vec.len(){}
code i am trying to do
ex :

pub struct Item {
    pub name: String,
    pub sell_in: i32,
    pub quality: i32,
}
    let items = vec![
        Item::new("+5 Dexterity Vest", 10, 20),
        Item::new("Aged Brie", 2, 0),
        Item::new("Elixir of the Mongoose", 5, 7),
        Item::new("Sulfuras, Hand of Ragnaros", 0, 80),
        Item::new("Sulfuras, Hand of Ragnaros", -1, 80),
        Item::new("Backstage passes to a TAFKAL80ETC concert", 15, 20),
        Item::new("Backstage passes to a TAFKAL80ETC concert", 10, 49),
        Item::new("Backstage passes to a TAFKAL80ETC concert", 5, 49),
        Item::new("Conjured Mana Cake", 3, 6),
    ];
    pub fn update_quality(&mut self) {
        let back_stage_iter: Vec<&Item> = self
            .items
            .iter()
            .filter(|&x| {
                x.name == "Backstage passes to a TAFKAL80ETC concert"
                    && x.sell_in < 11
                    && x.quality < 50
            })
            .collect();

        for v in back_stage_iter {
            *v.quality = *v.quality + 1;
        }

In the above *v.quality=*v.quality+1 am getting me can not assign a value to a reference.

iterators are "lazy", they encapsulate the transient states needed during the iteration, for example, conceptually, an iterator for Vec contains the equivalent information of the "current" index and a reference to the original data in the Vec (this is a conceptual model, not exactly the same as the actual implementation).

iterators don't "produce" results themselves, you must advance or consume the iterator to get the desired results. for example, calling the Iterator::next() method is "advancing" it, and calling "Iterator::collect()" is "consuming" it.

you don't need to "collect" the iterator into a collectoin if you don't need the intermediate Vec, you simply iterator through the iterator directly, it is called an "iterator" for a reason.

what you get out of an iterator depends on the iterator type, namely, the Iterator::Item associated type. for example, the iterator returned by vec.iter() has the Item type of &T, where vec is of type Vec<T>, while the iterator returned by vec.iter_mut() has the Item type of &mut T.

when you use for loop, it is desugared using the IntoIterator trait, and for Vec<T>, vec.into_iter() returns an iterator with Item being T. in your example, the ypte of back_stage_iter is Vec<&Item>, so when you do for v in back_stage_iter { ... }, v has the type of &Item, which is a shared (a.k.a. immutable) reference to Item, thus you cannot update the v.quality field through it.

use iter_mut() allows you iterate the collection with an exclusive (a.k.a mutable) reference:

fn update_quality(&mut self) {
    // no ".collect()" needed
    for v in self.items.iter_mut().filter(|x| ...) {
        // here `v` has type `&mut Item
        // you can use `+=` operator to increase its value
        v.quality += 1;
    }
}
2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.