我正在尝试编写一个函数,它将任何可迭代的泛型类型作为输入并循环遍历元素。这是一个工作示例
pub fn test1<'a, IterableT, ItemT>(nodes: &'a IterableT)
where
&'a IterableT: IntoIterator<Item = &'a ItemT>,
ItemT: 'a + Debug
{
for x in nodes {
println!("consuming or iterating: {:?}!", x);
}
}
这适用于引用类型。我努力实现一个既适用于常规类型又适用于引用的版本。我得到的最接近的是以下
pub fn test1<IterableT>(nodes: IterableT)
where
IterableT: IntoIterator,
IterableT::Item: Debug
{
for x in nodes {
println!("consuming or iterating: {:?}!", x);
}
}
只要我使用的类型的参考版本实现了 IntoIterator(例如
vec
、&vec
和 &mut vec
),此方法就有效。问题是我无法重新引入 ItemT
泛型,因为那时底层 Item
已缩小为 Item
或 &Item
之一
pub fn test1<IterableT, ItemT>(nodes: IterableT)
where
IterableT: IntoIterator<Item = ItemT>, // alternatively IntoIterator<Item = &ItemT>
ItemT: Debug
{
for x in nodes {
println!("consuming or iterating: {:?}!", x);
}
}
根据我使用的是
IntoIterator<Item = ItemT>
还是IntoIterator<Item = &ItemT>
,这适用于vec
或&vec
,但不能同时使用。一个巧妙的解决方法是指定 IterableT::Item: Into<ItemT>
,但这仅在底层类型实现 Into 特征时才有效(因此这适用于 i32、i64 等内置类型,但不适用于某些自定义结构)。
有没有办法表明
Item
可以是ItemT
或&ItemT
子句中的where
?我需要引入 ItemT
的原因是因为它是该函数所属父结构的通用变量。我需要专门接受该类型的迭代器。
std::borrow::Borrow
来治疗T
和&T
一样。
use std::{borrow::Borrow, fmt::Debug};
fn debug_iterator<I, T>(it: I)
where
I: IntoIterator,
I::Item: Borrow<T>,
T: Debug + ?Sized,
{
for item in it.into_iter() {
println!(" item: {:?}", item.borrow());
}
}
行动中:
fn main() {
let v1 = vec![String::from("hello"), String::from("world")];
println!("By reference:");
debug_iterator::<_, String>(v1.iter());
println!("By value:");
debug_iterator::<_, String>(v1);
}
输出:
By reference:
item: "hello"
item: "world"
By value:
item: "hello"
item: "world"
请注意,由于
Borrow
特征具有类型参数,因此您必须在调用站点显式地为 T
提供正确的类型; Rust 将无法推断出你想要的类型。