Как обновить все значения в BTreeSet? - PullRequest
0 голосов
/ 14 февраля 2019

У меня есть коллекция, которая является полем в структуре в некотором модуле.Я хочу обновить все значения в коллекции из другого модуля.

Я написал некоторый код, имитирующий то, чего я хочу достичь.Он немного укорочен, но я думаю, что в нем есть все необходимые детали.В этом коде нет структуры, содержащей коллекцию, но представьте, что это метод получения, который возвращает коллекцию.Я добавил в комментариях, как я думаю, это должно выглядеть.

pub mod pos {
    use std::cmp::{Ordering, PartialEq};

    #[derive(PartialOrd, PartialEq, Eq, Hash, Debug, Copy, Clone)]
    pub struct Pos {
        pub x: i32,
        pub y: i32,
    }

    #[allow(dead_code)]
    impl Pos {
        pub fn of(x: i32, y: i32) -> Self {
            Self { x, y }
        }

        pub fn offset(&mut self, pos: &Self) -> Self {
            self.x += pos.x;
            self.y += pos.y;

            *self
        }
    }

    impl Ord for Pos {
        fn cmp(&self, other: &Self) -> Ordering {
            if self.x < other.x {
                Ordering::Less
            } else if self.eq(other) {
                Ordering::Equal
            } else {
                Ordering::Greater
            }
        }
    }
}

mod test {
    use crate::pos::Pos;
    use std::collections::BTreeSet;

    #[test]
    fn test_iterators() {
        let mut data_in_some_strct: BTreeSet<Pos> = BTreeSet::new();

        data_in_some_strct.insert(Pos::of(1, 1));
        data_in_some_strct.insert(Pos::of(2, 2));
        data_in_some_strct.insert(Pos::of(3, 3));
        data_in_some_strct.insert(Pos::of(4, 4));

        // mimic getter call ( get_data(&mut self) -> &BTreeSet<Pos> {...}
        //    let set = data_in_some_strct;   // works, but not a reference
        let set = &data_in_some_strct; // doesn't work, How to adjust code to make it work??

        data_in_some_strct = set
            .into_iter()
            .map(|mut p| p.offset(&Pos::of(1, 0)))
            .inspect(|p| println!("{:?}", *p))
            .collect();

        assert_eq!(data_in_some_strct.contains(&Pos::of(2, 1)), true);
        assert_eq!(data_in_some_strct.contains(&Pos::of(3, 2)), true);
        assert_eq!(data_in_some_strct.contains(&Pos::of(4, 3)), true);
        assert_eq!(data_in_some_strct.contains(&Pos::of(5, 4)), true);
    }
}

Детская площадка

error[E0596]: cannot borrow `*p` as mutable, as it is behind a `&` reference
  --> src/lib.rs:56:26
   |
56 |             .map(|mut p| p.offset(&Pos::of(1, 0)))
   |                       -  ^ `p` is a `&` reference, so the data it refers to cannot be borrowed as mutable
   |                       |
   |                       help: consider changing this to be a mutable reference: `&mut pos::Pos`

Мне удалось заставить его работать без заимствований, но я бы хотелзаставить его работать с заимствованиями.Я предполагаю, что есть больше чем один способ достигнуть этого.Комментарии, чтобы помочь моей Rust мозговые дендриты подключения приветствуются.

Ответы [ 2 ]

0 голосов
/ 14 февраля 2019

Вы не можете изменить элементы, которые являются частью HashSet или BTreeSet, потому что значение элементов определяет, как они хранятся и доступны.Если вы их мутируете, то, как Stargateur упомянул , вы нарушите механику коллекции.В случае HashSet вы бы изменили хеш элемента, который определяет место, где хранятся данные.В случае BTreeSet алгоритм основан на том, как элементы сортируются.

Вы можете сделать это, взяв на себя ответственность, потому что вы используете оригинальный набор и производите новый, правильно сформированный набор.,Вы не можете вступить во владение заимствованным значением, потому что оно оставит за собой висячий указатель, чего не позволит вам сделать Rust.

Одним из возможных решений является временная замена исходного набора на пустой.Затем вы можете стать владельцем его содержимого, как в рабочем коде, и, наконец, записать обновленный набор поверх исходного:

let set = std::mem::replace(&mut data_in_some_strct, BTreeSet::new());

data_in_some_strct = set.into_iter()
    .map(|mut p| p.offset(&Pos::of(1,0)))
    .inspect(|p| println!("{:?}", *p))
    .collect();
0 голосов
/ 14 февраля 2019

BTreeSet не реализует impl<'a, T> IntoIterator for &'a mut BTreeSet<T> (что сломало бы дерево).

Это можно сделать только с типами, которые реализуют IntoIterator с mut, какimpl<'a, T> IntoIterator for &'a mut Vec<T>, пример .

...