我正在尝试编写一个函数,它接收一个字符串向量的向量并返回所有连接在一起的向量,即它返回一个字符串向量。
到目前为止,我能做到最好的是以下内容:
然而,我对这个结果并不满意,因为似乎我应该能够从第一个
我更加想知道为什么
所以让我尝试追踪每个表达式的类型:
我假设类型推断器能够根据
我的理解是,通过使用
编辑2:经过猜测、查看API文档和使用this method来解密类型的漫长过程,我完全注释了它们(忽略生命周期)。
到目前为止,我能做到最好的是以下内容:
fn concat_vecs(vecs: Vec<Vec<String>>) -> Vec<String> {
let vals : Vec<&String> = vecs.iter().flat_map(|x| x.into_iter()).collect();
vals.into_iter().map(|v: &String| v.to_owned()).collect()
}
然而,我对这个结果并不满意,因为似乎我应该能够从第一个
collect
调用中得到Vec<String>
,但是我无法弄清楚如何做到这一点。我更加想知道为什么
collect
的返回类型确切地是Vec<&String>
。我尝试从API文档和源代码中推断出这一点,但是尽管我已经尽力了,我甚至无法理解函数的签名。所以让我尝试追踪每个表达式的类型:
- vecs.iter(): Iter<T=Vec<String>, Item=Vec<String>>
- vecs.iter().flat_map(): FlatMap<I=Iter<Vec<String>>, U=???, F=FnMut(Vec<String>) -> U, Item=U>
- vecs.iter().flat_map().collect(): (B=??? : FromIterator<U>)
- vals was declared as Vec<&String>, therefore
vals == vecs.iter().flat_map().collect(): (B=Vec<&String> : FromIterator<U>). Therefore U=&String.
我假设类型推断器能够根据
vals
的类型推断出U=&String
。但是,如果我在代码中明确指定表达式的类型,则可以编译而不会出错:fn concat_vecs(vecs: Vec<Vec<String>>) -> Vec<String> {
let a: Iter<Vec<String>> = vecs.iter();
let b: FlatMap<Iter<Vec<String>>, Iter<String>, _> = a.flat_map(|x| x.into_iter());
let c = b.collect();
print_type_of(&c);
let vals : Vec<&String> = c;
vals.into_iter().map(|v: &String| v.to_owned()).collect()
}
显然,U=Iter<String>
...
请帮我澄清这个混乱。
编辑:得益于bluss的提示,我能够实现一个collect
如下所示:
fn concat_vecs(vecs: Vec<Vec<String>>) -> Vec<String> {
vecs.into_iter().flat_map(|x| x.into_iter()).collect()
}
我的理解是,通过使用
into_iter
,我将vecs
的所有权转移给IntoIter
,并向下传递调用链,这使我避免了在lambda调用中复制数据,因此 - 神奇地 - 类型系统为我提供了Vec<String>
,而以前它总是给我Vec<&String>
。虽然看到高级概念如何反映在库的工作方式上确实非常酷,但我希望我知道这是如何实现的。编辑2:经过猜测、查看API文档和使用this method来解密类型的漫长过程,我完全注释了它们(忽略生命周期)。
fn concat_vecs(vecs: Vec<Vec<String>>) -> Vec<String> {
let a: Iter<Vec<String>> = vecs.iter();
let f : &Fn(&Vec<String>) -> Iter<String> = &|x: &Vec<String>| x.into_iter();
let b: FlatMap<Iter<Vec<String>>, Iter<String>, &Fn(&Vec<String>) -> Iter<String>> = a.flat_map(f);
let vals : Vec<&String> = b.collect();
vals.into_iter().map(|v: &String| v.to_owned()).collect()
}
vecs.iter():Iter<T = Vec<String>,Item = Vec<String>>
:这是不正确的。结构体Iter
上没有名为Item
的关联类型(只有特征可以有关联类型)。vecs.iter()
的类型为Iter<Vec<String>>
,但是此类型实现了Iterator<Item=&Vec<String>>
(请注意&
)。当您使用flat_map
时,将&Vec<String>
转换为&String
。