在迭代器中找到第一个特定的枚举变体并对其进行转换

时间:2018-03-05 16:04:01

标签: vector enums rust find

我有一个包含不同变体的枚举,我希望找到匹配的第一个变体,然后通过返回变量值或将其映射到其他变换值来变换它。

在Scala中,我会使用案例类来执行以下操作:

data.collectFirst{ case d: DataD => d.data }

在Rust中,我必须两次模式匹配以获得相同的结果。有没有办法让它不那么冗长?

enum MyData {
    DataA(String),
    DataB(u64),
    DataC(bool),
    DataD { data: String, val: u32 },
}

fn main() {
    // test data
    let data = vec![
        MyData::DataB(42),
        MyData::DataD {
            data: "meaning of life".to_owned(),
            val: 42,
        },
        MyData::DataC(false),
    ];

    // find first one that matches and map it
    let found: Option<String> = data.iter()
        .find(|d| match **d {
            MyData::DataD { .. } => true,
            _ => false,
        })
        .and_then(|d| match *d {
            MyData::DataD { ref data, .. } => Some(data.to_owned()),
            _ => None,
        });
}

1 个答案:

答案 0 :(得分:5)

您可以使用Iterator::filter_map

public void changeSize(final Pane pane, double width, double height) {
    Duration cycleDuration = Duration.millis(500);
    Timeline timeline = new Timeline(
            new KeyFrame(cycleDuration,
                    new KeyValue(pane.maxWidthProperty(),width,Interpolator.EASE_BOTH)),
            new KeyFrame(cycleDuration,
                    new KeyValue(pane.maxHeightProperty(),height,Interpolator.EASE_BOTH))
            );

    timeline.play();
    timeline.setOnFinished(event->{
       /* insert code here if you need */
    });
}

我不太喜欢在我的迭代器链中使用大let found: Option<String> = data.iter() .filter_map(|d| { match *d { MyData::DataD { ref data, .. } => Some(data.to_owned()), _ => None, } }) .next(); 个语句,所以我通常会在match上创建一个方法来代替:

MyData

事实上,我的很多枚举都有这种模式:

enum MyData {
    DataA(String),
    DataB(u64),
    DataC(bool),
    DataD { data: String, val: u32 },
}

impl MyData {
    fn as_data_d_data(&self) -> Option<&str> {
        match *self {
            MyData::DataD { ref data, .. } => Some(data),
            _ => None,
        }
    }
}

fn main() {
    let data = vec![
        MyData::DataB(42),
        MyData::DataD {
            data: "meaning of life".to_owned(),
            val: 42,
        },
        MyData::DataC(false),
    ];

    let found: Option<String> = data.iter()
        .filter_map(MyData::as_data_d_data)
        .map(str::to_owned)
        .next();
}

我甚至创建了一个自动导出这些功能的箱子。我从来没有发表它,因为我很确定类似的东西已经存在,而我却找不到它......