首页 > 解决方案 > 如何仅映射迭代器中的 Some() 值?

问题描述

以下两项都有效(在 2 次调用中),但感觉过于冗长。


fn main() {
    let v = vec![Some(0), Some(1), None, Some(2)];
    assert_eq!(
        vec![0,2,4],
        v.iter()
            .filter(|x| x.is_some())
            .map(|x| x.unwrap() * 2)
            .collect::<Vec<u8>>());
    assert_eq!(
        vec![0,2,4],
        v.iter()
            .filter_map(|x| *x)
            .map(|x| x*2)
            .collect::<Vec<u8>>());
}

filter_map接近我想要的:

[filter_map] 自动移除选项层。如果您的映射已经返回一个选项并且您想跳过无,那么 filter_map 使用起来要好得多。

doc.rust-lang.org

但它不会解开闭包中的值,因为它期望返回一个选项。

有没有办法既过滤 Some 值,又通过一次调用映射这些值? 如:

// Fake, does not work
fn main() {
    let v = vec![Some(0), Some(1), None, Some(2)];
    assert_eq!(
        vec![0,2,4],
        v.iter()
            .map_only_some(|x| x * 2)
            .collect::<Vec<u8>>());
}

标签: rust

解决方案


好吧,我想通了,Iterator 的 next 总是返回一个 Option,所以你只需要展平它:

// Since v.iter().next() is Some(Some(0)), the following works
    assert_eq!(
        vec![0,2,4],
        v.iter()
            .flatten()
            .map(|x| x * 2)
            .collect::<Vec<u8>>());

它不是在一次调用中,但它更干净,而且我认为是惯用的。


推荐阅读