我正在尝试解析一系列 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())
}
但当然 try 不会逃脱 map()
出错而不是 Result<Vec<Video>,_>
, 我得到 Vec<Result<Video,_>>
.我可以将其重写为手动迭代将元素添加到新的 vec 中,但我觉得我缺少一些更简单的处理方法。
是否有一些现有的功能可以让我从 Iter<Result<T>>
至 Result<Vec<T>,_>
容易吗?
在函数式编程语言中,您可以将选项和结果视为容器,Rust 也是类似的,因此您可以对它们进行 map
/flat_map
。您可以使用 flat_map
来做到这一点。如果 videos
已经是一个向量,您可以根据 flat_map
ped 长度测试 Ok
的预期数量来决定是否返回 确定
。
但是,您应该尽量保持惰性,不要在第一次失败后继续解析。 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("not_ok")
}
}
这里有一个懒惰的选项 -
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()