如何在 Rust 中为第三方库实现 Iterator

How to implement Iterator in Rust for third party library

我正在尝试完成以下工作

use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let json = reqwest::get("https://www.bitmex.com/api/v1/instrument/indices")
        .await?
        .json::<serde_json::Value>()
        .await?;

    for key in json {
        println!("{:?}", key["symbol"]);
    }

    Ok(())
}

结果如下

--> src/main.rs:8:16
  |
8 |     for key in json {
  |                ^^^^ `Value` is not an iterator
  |
  = help: the trait `Iterator` is not implemented for `Value`
  = note: required because of the requirements on the impl of `IntoIterator` for `Value`

我尝试在本地源文件中实现它 serde_json-1.0.79/src/value/mod.rs as


impl IntoIterator for Value {
    type Item = Value;
    type IntoIter = ValueIterator;
    fn into_iter(self) -> Self::IntoIter {
        ValueIterator {
            slice: self.as_array().unwrap().iter(),
        }
    }
}

struct ValueIterator {
    slice: std::slice::Iter<Value>,
}

impl Iterator for ValueIterator {
    type Item = Value;

    fn next(&mut self) -> Option<Self::Item> {
        self.slice.next()
    }
}

但错误仍然存​​在,我可以在迭代器实现中更改什么以使代码按原样工作?

你不能。在为它实现特征之前,您需要先将它包装在您的板条箱中定义的新类型。解决这个问题的简单方法是创建一个新特征,您可以在执行您想要的操作的外部类型上实现。或者,您可以将其包装在 struct 中以完全避免限制。

pub trait ValueExt {
    type ArrayIter: IntoIter<Item=Foo>;
    fn json_array_iter(&self) -> Self::ArrayIter;
}

impl ValueExt for Value {
    type ArrayIter = ValueIterator;

    fn json_array_iter(&self) -> Self::ArrayIter {
        ValueIterator {
            slice: self.as_array().unwrap().iter(),
        }
    }
}

// Now you can call your trait while iterating
for item in value.json_array_iter() {
    // etc.
}

也就是说,serde_json 的解决方案是先扩展 Value 以检查它是否是一个数组,然后再遍历元素。

if let Value::Array(elements) = value_to_iterate {
    for item in elements {
        // etc.
    }
}

编辑:

为了好玩,这里有一个迭代器,它将遍历 JSON 值的键值对。它适用于字符串(索引、UTF-8 字符)、数组(索引、值)和映射(键、值)。

for (key, value) in json_object.items().unwrap() {
    println!("Key: {:?}, Value: {:?}", key, value);
}

这是实际的实现,playground link

use std::iter::Enumerate;
use std::str::Chars;
use std::slice::Iter;
use serde_json::{json, Value};
use serde_json::map::Iter as MapIter;

pub enum KVIter<'a> {
    StrIter ( Enumerate<Chars<'a>>),
    ArrIter (Enumerate<Iter<'a, Value>>),
    MapIter (MapIter<'a>),
}

impl<'a> Iterator for KVIter<'a> {
    type Item = (Value, Value);
    
    fn next(&mut self) -> Option<Self::Item> {
        match self {
            Self::StrIter(chars) => {
                let (idx, character) = chars.next()?;
                Some((json!(idx), json!(character)))
            }
            Self::ArrIter(values) => {
                let (idx, value) = values.next()?;
                Some((json!(idx), value.clone()))
            }
            Self::MapIter(items) => {
                let (key, value) = items.next()?;
                Some((json!(key), value.clone()))
            }
        }
    }
}

pub trait IntoKVIter {
    fn items(&self) -> Option<KVIter>;
}

impl<'a> IntoKVIter for Value {
    fn items(&self) -> Option<KVIter> {
        Some(match self {
            Value::String(string) => KVIter::StrIter(string.chars().enumerate()),
            Value::Array(values) => KVIter::ArrIter(values.into_iter().enumerate()),
            Value::Object(map) => KVIter::MapIter(map.into_iter()),
            _ => return None,
        })
    }
}