为何在Rust中对切片和范围使用filter时会出现不同的参数类型?
为什么数组切片和Range的filter闭包解引用次数不同?
嘿,这个问题的核心在于不同迭代器产出的元素类型不一样,咱们一步步拆解清楚:
1. 数组切片的iter()迭代器逻辑
你定义的数组a = [0,1,2,3],调用a.iter()时,返回的是std::slice::Iter<i32>类型的迭代器——它的设计是避免移动数组元素,所以每次产出的是数组元素的引用(也就是&i32)。
而filter方法的闭包参数,接收的是迭代器元素的引用(相当于给迭代器的Item再套一层引用)。所以这里闭包参数x的实际类型是&&i32:
- 第一次解引用
*x得到的是迭代器原本产出的&i32 - 第二次解引用
**x才拿到原始的i32数值,因此需要写**x > 1
最后collect()得到Vec<&i32>,是因为迭代器的元素本身就是&i32,收集后自然保留这个类型。
2. Range迭代器的逻辑
再看b = 0..4,这是Range<i32>类型,它的迭代器直接产出原始的i32值(不是引用)。
同样遵循filter的规则:闭包参数是迭代器元素的引用,也就是&i32,所以只需要一次解引用*x就能拿到i32数值,写成*x > 1就足够了。
而collect()得到Vec<i32>,是因为Range迭代器的元素是i32,filter不会改变元素类型,收集后自然就是i32的向量。
简化写法小技巧
其实可以用模式匹配或者迭代器适配器来避免多层解引用的困惑:
数组切片的filter可以用模式匹配直接绑定原始值:
let a_iter = a.iter().filter(|&&x| x > 1);这里通过
&&x直接把原始i32值绑定到x上,直接写x>1就行。或者先把迭代器转成产出值的类型:
let a_iter = a.iter().copied().filter(|x| x > 1); let x: Vec<i32> = a_iter.collect();copied()会把&i32复制成i32,后续filter闭包参数就是&i32,直接用x>1也没问题。
内容的提问来源于stack exchange,提问作者lemon
相关产品推荐
相关产品推荐

