How to lazily create map entry whose construction uses self in Rust

前端 未结 2 1674
别跟我提以往
别跟我提以往 2021-01-06 02:40

I\'m trying to implement a lazy-construction / memoized evaluation / caching idiom in Rust.

There\'s an outer type which has a bunch of data and an accessor method.

2条回答
  •  离开以前
    2021-01-06 03:03

    The answer is that it depends on specifically which state you need access to in the or_insert_with closure. The problem is that or_insert_with definitely cannot have access to the map itself because the entry api takes a mutable borrow of the map.

    If all you need for ContainedThing::create is just the size of the map, then you'll just need to calculate the map size ahead of time.

    impl Thing {
        pub fn get(&mut self, key: i32) -> &ContainedThing {
            let map_size = self.map.len();
            self.map.entry(&key).or_insert_with(|| {
                // The call to entry takes a mutable reference to the map,
                // so you cannot borrow map again in here
                ContainedThing::create(map_size)
            })
        }
    }
    

    I think the spirit of the question was more about general strategies, though, so let's assume there's some other state within Thing that is also required to create ContainedThing.

    struct Thing {
        map: HashMap,
        some_other_stuff: AnotherType, //assume that this other state is also required in order to create ContainedThing
    }
    
    impl Thing {
        pub fn get(&mut self, key: i32) -> &ContainedThing {
            //this is the borrow of self
            let Thing {
                ref mut map,
                ref mut some_other_stuff,
            } = *self;
    
            let map_size = map.len();
            map.entry(key).or_insert_with(|| {
                // map.entry now only borrows map instead of self
                // Here you're free to borrow any other members of Thing apart from map
                ContainedThing::create(map_size, some_other_stuff)
            })
        }
    }
    

    Whether that's really cleaner than your other solution of manually checking if self.map.contains_key(&key) is up for debate. Destructuring tends to be the strategy that I go for, though, to allow borrowing specific members of self instead of the entire struct.

提交回复
热议问题