Я пытаюсь обернуть HashMap
, как определено ниже, чтобы вернуть изменяемую ссылку из HashMap
:
use std::{collections::HashMap, marker::PhantomData};
struct Id<T>(usize, PhantomData<T>);
pub struct IdCollection<T>(HashMap<Id<T>, T>);
impl<'a, T> std::ops::Index<Id<T>> for &'a mut IdCollection<T> {
type Output = &'a mut T;
fn index(&mut self, id: &'a Id<T>) -> Self::Output {
self.0.get_mut(id).unwrap()
}
}
И полученная ошибка:
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 54:5...
--> src/id_container.rs:54:5
|
54 | / fn index(&mut self, id: &'a Id<T>) -> Self::Output {
55 | | self.0.get_mut(id).unwrap()
56 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/id_container.rs:55:9
|
55 | self.0.get_mut(id).unwrap()
| ^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 52:6...
--> src/id_container.rs:52:6
|
52 | impl<'a, T> std::ops::Index<Id<T>> for &'a mut IdCollection<T> {
| ^^
= note: ...so that the types are compatible:
expected std::ops::Index<id_container::Id<T>>
found std::ops::Index<id_container::Id<T>>
Почему компилятор не может продлить срок службы get_mut
? IdCollection
будет затем заимствовано.
Обратите внимание, что я попытался использовать std::collections::HashSet<IdWrapper<T>>
вместо HashMap
:
struct IdWrapper<T> {
id: Id<T>,
t: T,
}
Реализация правильного заимствования и т. Д., Чтобы я мог использовать Id<T>
в качестве ключа.
Однако HashSet
не предлагает изменяемый метод получения (что имеет смысл, поскольку вы не хотите изменять то, что используется для вашего хэша). Однако в моем случае только часть объекта должна быть неизменной. Приведение типа const
к типу, отличному от const
, является UB, так что об этом не может быть и речи.
Могу ли я достичь того, чего хочу? Нужно ли использовать какую-нибудь обертку, например Box
? Хотя я бы предпочел избежать любой косвенности ...
EDIT
Хорошо, я идиот. Сначала я пропустил IndexMut
вместо Index
и забыл &
при указании Self::Output
в подписи.
Вот мой полный код ниже:
pub struct Id<T>(usize, PhantomData<T>);
impl<T> std::fmt::Display for Id<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl<T> Hash for Id<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl<T> PartialEq for Id<T> {
fn eq(&self, o: &Self) -> bool {
self.0 == o.0
}
}
impl<T> Eq for Id<T> {}
pub struct IdCollection<T>(HashMap<Id<T>, T>);
impl<'a, T> IntoIterator for &'a IdCollection<T> {
type Item = (&'a Id<T>, &'a T);
type IntoIter = std::collections::hash_map::Iter<'a, Id<T>, T>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<'a, T> IntoIterator for &'a mut IdCollection<T> {
type Item = (&'a Id<T>, &'a mut T);
type IntoIter = std::collections::hash_map::IterMut<'a, Id<T>, T>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter_mut()
}
}
impl<T> std::ops::Index<Id<T>> for IdCollection<T> {
type Output = T;
fn index(&self, id: Id<T>) -> &Self::Output {
self.0.get(&id).unwrap()
}
}
impl<T> std::ops::IndexMut<Id<T>> for IdCollection<T> {
fn index_mut(&mut self, id: Id<T>) -> &mut Self::Output {
self.0.get_mut(&id).unwrap()
}
}
impl<T> std::ops::Index<&Id<T>> for IdCollection<T> {
type Output = T;
fn index(&self, id: &Id<T>) -> &Self::Output {
self.0.get(id).unwrap()
}
}
impl<T> std::ops::IndexMut<&Id<T>> for IdCollection<T> {
fn index_mut(&mut self, id: &Id<T>) -> &mut Self::Output {
self.0.get_mut(id).unwrap()
}
}