나는 몇 가지 방법을 포장하고 싶습니다 HashMap
등을 insert
하고 keys
. 이 시도가 컴파일되고 테스트가 통과됩니다.
use std::collections::HashMap;
use std::hash::Hash;
pub trait Map<'a, N: 'a> {
type ItemIterator: Iterator<Item=&'a N>;
fn items(&'a self) -> Self::ItemIterator;
fn insert(&mut self, item: N);
}
struct MyMap<N> {
map: HashMap<N, ()>
}
impl<N: Eq + Hash> MyMap<N> {
fn new() -> Self {
MyMap { map: HashMap::new() }
}
}
impl<'a, N: 'a + Eq + Hash> Map<'a, N> for MyMap<N> {
type ItemIterator = std::collections::hash_map::Keys<'a, N, ()>;
fn items(&'a self) -> Self::ItemIterator {
self.map.keys()
}
fn insert(&mut self, item: N) {
self.map.insert(item, ());
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Eq, Hash, PartialEq, Debug)]
struct MyItem;
#[test]
fn test() {
let mut map = MyMap::new();
let item = MyItem { };
map.insert(&item);
let foo = map.items().collect::<Vec<_>>();
for it_item in map.items() {
assert_eq!(it_item, &&item);
}
assert_eq!(foo, vec![&&item]);
}
}
Map
가능한 경우 수명 매개 변수의 필요성을 제거하고 싶지만 지금까지 방법을 찾지 못했습니다. 이 문제 std::collections::hash_map::Keys
는 수명 매개 변수가 필요한 의 정의에서 비롯된 것 같습니다 .
Map
에 수명 매개 변수를 제공해야 할 때까지 특성 작업 을 재정의하려고 시도합니다 Keys
.
use std::collections::HashMap;
use std::hash::Hash;
pub trait Map<N> {
type ItemIterator: Iterator<Item=N>;
fn items(&self) -> Self::ItemIterator;
fn insert(&mut self, item: N);
}
struct MyMap<N> {
map: HashMap<N, ()>
}
impl<N: Eq + Hash> MyMap<N> {
fn new() -> Self {
MyMap { map: HashMap::new() }
}
}
// ERROR: "unconstrained lifetime parameter"
impl<'a, N> Map<N> for MyMap<N> {
type ItemIterator = std::collections::hash_map::Keys<'a, N, ()>;
}
컴파일러는 수명을 Map
특성에 다시 도입하지 않고 수정할 수 없었던 제약없는 수명 매개 변수에 대한 오류를 발행합니다 .
이 실험의 주요 목표는 Box
이전 시도에서 제거 할 수있는 방법을 확인하는 것이 었습니다 . 이 질문에서 설명하는 것처럼 반복자를 반환하는 또 다른 방법입니다. 그래서 지금은 그 접근 방식에 관심이 없습니다.
수명 매개 변수 를 도입하거나 사용 하지 않고 어떻게 설정하고 Map
구현할 수Box
있습니까?
생각해야 할 점 hash_map::Keys
은 일반적인 수명 매개 변수가 있기 때문에 어떤 이유로 든 필요할 수 있으므로 추상화하는 특성이 Keys
필요할 것입니다.
이 경우의 정의에서 의 수명 Map
을 지정하는 방법이 필요 합니다. ( 입니다 ).ItemIterator
Item
Item
&'a N
이것이 당신의 정의였습니다.
type ItemIterator: Iterator<Item=&'a N>
을 구현하는 모든 구조체에 대해 Map
연결된 구조체 ItemIterator
가 참조의 반복자 여야 한다고 말하려고 합니다. 그러나이 제약은 추가 정보 없이는 쓸모가 없습니다. 참조가 얼마나 오래 지속되는지 알아야합니다 (따라서 type ItemIterator: Iterator<Item=&N>
오류가 발생하는 이유 :이 정보가 누락되었으며 현재 AFAIK를 제거 할 수 없음).
따라서 'a
각각의 &'a N
유효 기간을 보장하는 일반적인 수명의 이름을 지정합니다 . 이제 차용 검사기를 충족하고에 &'a N
대해 유효 함을 증명하고에 대한 'a
몇 가지 유용한 약속을 설정 'a
하려면 다음을 지정합니다.
&self
제공된 참조에 대한 모든 값 items()
은 최소한 'a
. 이렇게하면 반환 된 각 항목 ( &'a N
) &self
에 대해 항목 참조가 유효한 상태를 유지하기 위해 참조가 여전히 유효해야합니다 self
. 즉, 항목이 오래 지속되어야합니다 . 이 불변성을 사용하면 &self
의 반환 값에서 참조 할 수 있습니다 items()
. 으로 이것을 지정했습니다 fn items(&'a self)
. (참고 : my_map.items()
는 실제로를 약칭합니다 MyMap::items(&my_map)
.)N
의 자체도 유효 기간 동안 유효해야합니다 'a
. 이것은 객체가 영원히 살지 않는 'static
참조 (비 참조 라고도 함 )를 포함하는 경우 중요합니다 . 이렇게하면 항목에 N
포함 된 모든 참조가 최소한 'a
. 제약 조건과 함께 이것을 지정했습니다 N: 'a
.요약하자면,의 정의 Map<'a, N>
는 구현 자의 items()
함수 ItemIterator
가에 유효한 'a
항목에 대해 유효한 참조를 반환해야합니다 'a
. 이제 구현 :
impl<'a, N: 'a + Eq + Hash> Map<'a, N> for MyMap<N> { ... }
당신이 볼 수 있듯이, 'a
당신이 어떤 사용할 수 있도록 매개 변수는 완전히 구속되지이다 'a
의 방법에 Map
의 인스턴스를 MyMap
만큼으로, N
의의 제약 조건을 충족 N: 'a + Eq + Hash
. 전달 된지도가 모두 유효한 'a
가장 긴 수명이 자동으로되어야 합니다.N
items()
어쨌든, 여기서 설명하는 것은 스트리밍 반복기로 알려져 있으며 수년 동안 문제가되어 왔습니다. 일부 관련 토론은 승인되었지만 현재 구현되지 않은 RFC 1598을 참조하십시오 (하지만 압도 될 준비가되어 있음).
마지막으로, 일부 사람들이 언급했듯이, Map
.NET에 대한 기본 제공 IntoIterator<Item=&'a N>
및 별도의 특성 의 조합으로 더 잘 표현 될 수 있으므로 처음부터 특성이 나쁜 디자인 일 수 있습니다 insert()
. 이것은 for
루프 등에서 사용되는 기본 반복기 가 내장 반복기와 일치하지 않는 항목 반복자가 될 것이라는 것을 의미 HashMap
하지만, 귀하의 특성의 목적이 완전히 명확하지 않으므로 귀하의 디자인이 의미가 있다고 생각합니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다