我试图解析一系列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>,_>
?
答案 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()