我写了一个方法:
fn foo(input: HashMap<String, Vec<String>>) {...}
然后我意识到,为了编写测试,我想控制迭代顺序(可能是BTreeMap或LinkedHashMap).这导致了两个问题:
>我可以使用哪些特性或特征组合基本上表达“字符串到字符串向量的映射”?我没有在HashMap的文档中看到任何有希望的东西.
>事实证明,在这个方法中,我只想迭代映射条目,然后迭代每个字符串向量中的项目,但无法找出用于指定它的正确语法.写这个的正确方法是什么?
fn foo(input: IntoIterator<(String, IntoIterator<String>)>) {...}
最佳答案 描述抽象的HashMap没有这样的特性.我相信没有计划制作一个.到目前为止,最好的答案是你的#2建议:对于只读的HashMap,你可能只想要迭代一些东西.
要在语法级别回答,您尝试编写:
fn foo(input: IntoIterator<(String, IntoIterator<String>)>)
但这是无效的,因为IntoIterator没有模板参数:
pub trait IntoIterator where Self::IntoIter::Item == Self::Item {
type Item;
type IntoIter: Iterator;
fn into_iter(self) -> Self::IntoIter;
}
然而,它需要两个相关的类型,所以你真正想表达的可能是以下内容(内部我将嵌套的IntoIterator更改为Vec的具体类型以简化):
fn foo<I>(input: I)
where I: IntoIterator<
Item=(String, Vec<String>),
IntoIter=IntoIter<String, Vec<String>>>
然而,如果IntoIterator并不总是合适的话,那就是选择,因为它意味着所有权的转移.如果你只是想借用HashMap用于只读目的,你可能会更好地使用HashMap的标准迭代器特性,Iterator< Item =(&’a String,&’vec< String>)> ;.
fn foo_iter<'a, I>(input: I)
where I: Iterator<Item=(&'a String, &'a Vec<String>)>
与第一个版本不同,您可以通过请求新的迭代器多次使用它.
let mut h = HashMap::new();
h.insert("The Beatles".to_string(),
vec!["Come Together".to_string(),
"Twist And Shout".to_string()]);
h.insert("The Rolling Stones".to_string(),
vec!["Paint It Black".to_string(),
"Satisfaction".to_string()]);
foo_iter(h.iter());
foo_iter(h.iter());
foo(h);
//foo(h); <-- error: use of moved value: `h`
编辑
正如评论中所述,这里是嵌套的IntoIterators的foo版本,而不是更简单的Vec:
fn foo<I, IVecString>(input: I)
where
I: IntoIterator<
Item=(String, IVecString),
IntoIter=std::collections::hash_map::IntoIter<String, IVecString>>,
IVecString: IntoIterator<
Item=String,
IntoIter=std::vec::IntoIter<String>>