ссылкам на значения заимствованной итератором коллекции. Но сигнатура next() не позволяет использовать (&'a mut self)->'a. Для индексируемых по usize коллекций компилятор успокаивается на отправке &collection[i], но если условный collection имеет лишь свой .iter() - возникает заимствование от self, которое мне не нужно.
                  
                  
                  Задача - итерироваться по ссылкам на элементы коллекции, и при успешной обработке выбрасывать элемент (эдакий 'graceful' .drain()). Использую сейчас вариант с unsafe, который рекомендуют при удалении из set элемента, используя его же в качестве ключа, но хотелось бы без unsafe
                  
                  
                  
                  
                  
                  struct IdHashDeleteAfterUseIterator<'a, Id> where Id: Eq + Hash {
                  
                  
                      set: &'a mut HashSet<Id>,
                  
                  
                      first_done: bool,
                  
                  
                  }
                  
                  
                  impl<'a, Id> IdHashDeleteAfterUseIterator<'a, Id> where Id: Eq + Hash {
                  
                  
                      fn new (set: &'a mut HashSet<Id>) -> IdHashDeleteAfterUseIterator<'a, Id> {
                  
                  
                          IdHashDeleteAfterUseIterator {set, first_done: false}
                  
                  
                      }
                  
                  
                  }
                  
                  
                  impl<'a, Id> Iterator for IdHashDeleteAfterUseIterator<'a, Id>
                  
                  
                  where Id: Eq + Hash {
                  
                  
                      type Item = &'a Id;
                  
                  
                      fn next(&mut self) -> Option<Self::Item> {
                  
                  
                          if self.first_done {
                  
                  
                              if let Some(value_as_key) = self.set.iter().next() {
                  
                  
                                  // https://github.com/rust-lang/rust/issues/27804#issuecomment-406269067
                  
                  
                                  let key_ref = unsafe{&*(value_as_key as *const _)};
                  
                  
                                  self.set.remove(key_ref);
                  
                  
                              }
                  
                  
                          }
                  
                  
                          self.first_done = true;
                  
                  
                          //let opt = self.set.iter().next(); // error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
                  
                  
                          //opt
                  
                  
                          match self.set.iter().next() {
                  
                  
                              None => None,
                  
                  
                              Some(v) => {
                  
                  
                                  // зато работает
                  
                  
                                  let myref = unsafe{&*(v as *const _)};
                  
                  
                                  Some(myref)
                  
                  
                              }
                  
                  
                          }
                  
                  
                      }
                  
                  
                  }
                  
                  
                  Спасибо
                  
                  
                
Стандартный трейт Iterator для такого не подходит. Возвращаемая им ссылка должна быть валидна на протяжении всего времени жизни итератора. Здесь ссылка инвалидируется, что дает возможность сделать UB в safe коде. Например: let a = iter.next(); let _ = iter.next(); a.something();
Так ведь в моём случае эта ссылка и будет валидна всю жизнь итератора, и даже дольше, ведь коллекция по ссылке живёт дольше самой ссылки по-определению. С чего бы возвращаемой ссылке инвалидироваться? Пример с a.something() не ведёт к ub, ведь 1. Итератор до сих пор жив 2. Для моего исходника, даже после drop итератора, set, заимствованный итератором, останется жив Можно подробнее?
self.set.remove(key_ref); удаляет элемент, все ссылки на него, в том числе a из моего примера становятся невалидными.
Дошло, спасибо У меня по логике есть гарантия неиспользования элемента за пределами текущей итерации Выходит, следует использовать while let Some(v) = my_next(&mut my_id_hash_delete_after_use_iterator) { … } Где fn my_next<‘a>(set: MyIdHashDeteAfterUseIterator) -> Option<&’a Id> { … } Или существует паттерн получше?
Дрейнить и вставлять неиспользованные элементы обратно. Использовать другую структуру данных, а не HashSet
Обсуждают сегодня