如何在 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,
})
}
}
我正在尝试完成以下工作
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,
})
}
}