很好的方式来映射潜在的失败

时间:2016-08-09 02:34:26

标签: rust

我试图解析一系列Json个对象,这些对象的潜在失败会取消整个功能。

理想情况下,我会做类似的事情:

fn .... -> Result<Vec<Video>, YoutubeParseError> {
    ...
    let videos = try!(doc.find("items").
        and_then(Json::as_array).
        ok_or(YoutubeParseError));

    Ok(videos.into_iter().
        map(|item| try!(json_to_video(item))).
        collect())
}

但是当然尝试没有逃避map()错误,而不是Result<Vec<Video>,_>,我得到Vec<Result<Video,_>>。我可以将其重写为手动迭代,将元素添加到新的vec中,但我觉得我错过了一些更简单的处理方法。

是否有一些现有功能可以让我轻松地从Iter<Result<T>>转到Result<Vec<T>,_>

1 个答案:

答案 0 :(得分:0)

在函数式编程语言中,您可以将选项和结果视为容器,Rust也类似,因此您可以map / flat_map对它们进行处理。您可以使用flat_map执行此操作。如果videos已经是向量,您可以针对Ok长度测试flat_map的预期数量,以决定是否返回Ok。< / p>

但是,您应该尝试保持懒惰,并且在第一次失败后不要继续解析。 take_while将是一个选项。无论哪种方式,您都需要跟踪您是否在途中看到parse_failure。类似于下面的东西 - 它演示了flat_map如何删除Error,但它解析的不仅仅是必要的。您还可以使用.filter然后使用.map来获取解析结果

fn get_videos(test: &Vec<&str>) -> Result<Vec<u32>, &'static str> {
    let videos = ...
    let expected = videos.len();
    let extracted = v.into_iter().flat_map(|x| json_to_video(x)).collect();
    if extracted.len() == expected {
        Ok(extracted)
    } else {
        Err("__CANNOT_PARSE__")
    }
}

这是一个懒惰地做的选择 -

let extracted = videos.map(|x|json_to_video(x))
                      .take_while(|x|x.is_ok())
                      .map(|x|x.ok().unwrap())
                      .collect() 

您可以在第一次失败时放弃所有内容时调用unwrap。现在,如果Ok

,则返回extracted.len() == videos.len()