英文:
Returning a parametrized iterator over HashMap entries in stable Rust
问题
我试图扩展一个 Rust 容器(HashMap),添加一个类似于 iter() 的方法,该方法返回一个非拥有的迭代器。这个方法将遍历与 HashMap::iter() 相同的条目,但会过滤掉一些条目。我希望使用一个 &str 参数来参数化过滤(因此取决于参数,可能会跳过映射的一些、没有或所有的 (&k, &v) 条目)。
我决定使用扩展 trait 进行实现,并在新方法中使用 iter().filter_map()。
use std::collections::{hash_map, HashMap};
pub struct Section {}
pub trait HashMapExt<'a> {
type FilterMap: Iterator<Item = &'a Section>;
fn iter_sections(&'a self, path: &'static str) -> Self::FilterMap;
}
一个未捕获参数的虚构实现可以正常工作:
impl<'a> HashMapExt<'a> for HashMap<String, Section> {
type FilterMap = core::iter::FilterMap<hash_map::Iter<'a, String, Section>,
fn((&String, &'a Section))->Option<&'a Section>>;
fn iter_sections(&'a self, path: &str) -> Self::FilterMap {
self.iter().filter_map(|(k,v)| {
println!("do stuff"); // 模拟过滤
Some(v)
})
}
}
但是当我尝试捕获 "path" 时出现问题:
fn iter_sections(&'a self, path: &str) -> Self::FilterMap {
self.iter().filter_map(|(k,v)| {
path; // 模拟基于 "path" 的过滤
Some(v)
})
}
这导致了在 filter_map()
行出现错误:
error[E0308]: mismatched types
expected fn pointer, found closure
note: expected fn pointer `for<'r> fn((&'r String, &Section)) -> Option<&Section>`
found closure `[closure@src/main.rs:31:32: 31:57]`
我没有问题返回由闭包类型参数化的 FilterMap 类型,但问题是 Rust 中这个 [closure@src/main.rs...]
的东西没有类型名称。
这就是我的问题:我如何指定一个接受参数化过滤器的 trait 方法的返回类型,以便获得一个正常工作的 iter_sections() 方法?
我迄今为止尝试解决这个问题的努力:
- 我想也许使用非参数化的函数指针可以解决问题:
fn make_filter<'a>(path: &'static str) -> impl Fn((&String, &'a Section))->Option<&'a Section> {
move|(p, c)| {
path; // 模拟基于 "path" 的过滤
Some(c)
}
}
在使用时:
fn iter_sections(&'a self, path: &'static str) -> Self::FilterMap {
let filter = make_filter(path);
self.iter().filter_map(filter)
}
这并没有帮助:
error[E0308]: mismatched types
expected fn pointer, found opaque type
note: expected fn pointer `for<'r> fn((&'r String, &Section)) -> Option<&Section>`
found opaque type `impl for<'r> Fn<((&'r String, &Section),)>`
- 我尝试在 trait 实现中返回一个 "impl" 类型:
type FilterMap = core::iter::FilterMap<hash_map::Iter<'a, String, Section>,
impl Fn((&String, &'a Section))->Option<&'a Section>>;
显然在稳定版的 Rust 中不可行:
error[E0658]: `impl Trait` in type aliases is unstable
note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
我使用的是 Rust v1.48,所以这对我来说不是一个选择。我知道关于 "Box" 的解决方案(使 trait 处理 Box
英文:
I'm trying to extend a Rust container (HashMap) with a method that returns a non-owning iterator, similarly to iter(). This method would iterate over the same entries as HashMap::iter() but will filter out some entries. I want to parametrize the filtering with a &str parameter (so depending on the parameter, some, none, or all the map's (&k, &v) entries are stepped over).
I decided to use an extension trait for the implementation, and in the new method, just summon iter().filter_map().
use std::collections::{hash_map, HashMap};
pub struct Section {}
pub trait HashMapExt<'a> {
type FilterMap: Iterator<Item = &'a Section>;
fn iter_sections(&'a self, path: &'static str) -> Self::FilterMap;
}
A dummy implementation that is not capturing the parameter in a closure works fine:
impl<'a> HashMapExt<'a> for HashMap<String, Section> {
type FilterMap = core::iter::FilterMap<hash_map::Iter<'a, String, Section>,
fn((&String, &'a Section))->Option<&'a Section>>;
fn iter_sections(&'a self, path: &str) -> Self::FilterMap {
self.iter().filter_map(|(k,v)| {
println!("do stuff"); // Simulate filtering
Some(v)
})
}
}
Problems arise when I'm trying to capture "path":
fn iter_sections(&'a self, path: &str) -> Self::FilterMap {
self.iter().filter_map(|(k,v)| {
path; // simulate "path" based filtering
Some(v)
})
}
Which results in an error at the filter_map()
line:
error[E0308]: mismatched types
expected fn pointer, found closure
note: expected fn pointer `for<'r> fn((&'r String, &Section)) -> Option<&Section>`
found closure `[closure@src/main.rs:31:32: 31:57]`
I don't have any problem returning a FilterMap type parametrized by closure type, but the problem is that this [closure@src/main.rs...]
thing doesn't have a type name in Rust.
And that is my question: How do I specify the return type of a trait method that is accepting a parametrized filter so I get a working iter_sections() method?
My attempts to work around this issue so far:
- I thought that maybe using a non-parametric function pointer would resolve the issue:
fn make_filter<'a>(path: &'static str) -> impl Fn((&String,
&'a Section))->Option<&'a Section> {
move|(p, c)| {
path; // simulate "path" based filtering
Some(c)
}
}
used as:
fn iter_sections(&'a self, path: &'static str) -> Self::FilterMap {
let filter = make_filter(path);
self.iter().filter_map(filter)
}
Which doesn't help:
error[E0308]: mismatched types
expected fn pointer, found opaque type
note: expected fn pointer `for<'r> fn((&'r String, &Section)) -> Option<&Section>`
found opaque type `impl for<'r> Fn<((&'r String, &Section),)>`
- I attempted to return an "impl" type in the trait implementation:
type FilterMap = core::iter::FilterMap<hash_map::Iter<'a, String, Section>,
impl Fn((&String, &'a Section))->Option<&'a Section>>;
Which apparently isn't possible in stable Rust:
error[E0658]: `impl Trait` in type aliases is unstable
note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
I have Rust v1.48 so this is not an option for me.
I know about "Box" based solutions (make the trait deal in Box<dyn Trait> return values) but I'd like to avoid heap allocations whenever possible, and express the iterator type thru type manipulation.
答案1
得分: 2
以下是翻译好的代码部分:
use std::collections::hash_map::Iter as HmIter;
use std::collections::HashMap;
trait HashMapExt<K, V> {
fn iter_sections<'a>(&'a self, path: &'a str) -> IterSections<'a, K, V>;
}
struct IterSections<'a, K: 'a, V: 'a> {
path: &'a str,
map_iter: HmIter<'a, K, V>,
}
impl<'a, K: 'a, V: 'a> Iterator for IterSections<'a, K, V> {
type Item = <HmIter::<'a, K, V> as Iterator>::Item;
fn next(&mut self) -> Option<Self::Item> {
while let Some(res) = self.map_iter.next() {
// 模拟过滤
if self.path == "Hello" {
return Some(res);
}
}
None
}
}
impl<K, V> HashMapExt<K, V> for HashMap<K, V> {
fn iter_sections<'a>(&'a self, path: &'a str) -> IterSections<'a, K, V> {
IterSections {
path,
map_iter: self.iter(),
}
}
}
请注意,我已经保留了原始代码中的格式和注释。如果您有任何其他问题或需要进一步帮助,请告诉我。
英文:
You can implement filtering manually.
use std::collections::hash_map::Iter as HmIter;
use std::collections::HashMap;
trait HashMapExt<K, V>{
fn iter_sections<'a>(&'a self, path: &'a str)->IterSections<'a, K, V>;
}
struct IterSections<'a, K: 'a, V: 'a>{
path: &'a str,
map_iter: HmIter<'a, K, V>,
}
impl<'a, K: 'a, V: 'a> Iterator for IterSections<'a, K, V> {
type Item = <HmIter::<'a, K, V> as Iterator>::Item;
fn next(&mut self)->Option<Self::Item> {
while let Some(res) = self.map_iter.next(){
// Simulate filtering
if self.path == "Hello" {
return Some(res);
}
}
None
}
}
impl<K,V> HashMapExt<K,V> for HashMap<K,V>{
fn iter_sections<'a>(&'a self, path: &'a str)->IterSections<'a, K, V>{
IterSections{
path,
map_iter: self.iter(),
}
}
}
Probably, you should also implement fold/try_fold functions too.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论