在对包装 HashMap 的结构的引用上实现 IntoIterator

Jon*_*hon 3 iterator lifetime ownership rust borrow-checker

我正在尝试构建一种 HTTP Web 服务器作为学习练习,但在尝试使用 for 循环(通过实现IntoIterator)使我的其中一个类型可迭代时遇到了麻烦。

迄今为止

我创建了一个数据结构,其中我有一个Response对象(旨在模拟 HTTP 响应),并且包含一个Headers对象(旨在模拟 HTTP 响应标头),并且包含HashMap<String, String>,表示实际标头值:

use std::collections::HashMap;

struct Headers {
    headers: HashMap<String, String>,
}

impl Headers {
    pub fn new(headers: HashMap<String, String>) -> Self {
        Self { headers }
    }
}

struct Response {
    headers: Headers,
}

impl Response {
    pub fn new(headers: Headers) -> Self {
        Self { headers }
    }

    pub fn headers(&self) -> &Headers {
        &self.headers
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:该headers方法返回一个不可变的引用,因为我只想读取这些值。理想情况下,我不想复制/克隆标题以便可以读取它们。

目的

我想要做的是这样的:

fn main() {
    // just creating an example here
    let mut headers = HashMap::new();
    headers.insert("foo".to_string(), "one".to_string());
    headers.insert("bar".to_string(), "two".to_string());
    let response = Response::new(Headers::new(headers));

    // this is what I'm aiming for:
    for (key, value) in response.headers() {
        println!("{}: {}", key, value);
    }
}
Run Code Online (Sandbox Code Playgroud)

我尝试过的

我已经尝试了很多方法来使其正常工作,但到目前为止我都失败了。到目前为止,我最接近的是实现IntoIteratorfor&Headers然后调用into_iter()哈希图:

impl IntoIterator for &Headers {
    type Item = (String, String);
    type IntoIter = IntoIter<String, String>;

    fn into_iter(self) -> Self::IntoIter {
        self.headers.into_iter()
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,这会导致错误:

无法移出self.headers共享引用后面的内容

我尝试四处搜索,发现了许多类似的 StackOverflow 问题,但似乎没有一个能回答我的确切问题。

谢谢。

isa*_*tfa 6

您现在正在做的是委托IntoIterator实施HashMap<String, String>. 但是您需要委托给 的实现,IntoIterator因为&HashMap<String, String>您无法获得self.headerswhenself的引用的拥有版本。

不过,谢天谢地,这是一个简单的修复:

// Just giving this type a concise name so we can reference it easyily later
type HeaderMap = HashMap<String, String>;


impl<'h> IntoIterator for &'h Headers {
    // Here we just tell Rust to use the types we're delegating to.
    // This is just (&'h String, &'h String)
    type Item = <&'h HeaderMap as IntoIterator>::Item;
    type IntoIter = <&'h HeaderMap as IntoIterator>::IntoIter;

    fn into_iter(self) -> Self::IntoIter {
        // Now just call `into_iter` on the correct thing
        (&self.headers).into_iter()
        // self.headers.iter() would work just as well here
    }
}
Run Code Online (Sandbox Code Playgroud)