1

我试图.iter()在与 结合使用时进行错误处理.flat_map,其中包含一个.iter().map()

该场景正在获取Event属于一组组织的所有 s,其中嵌套.iter().map()用于获取每个事件的参与者,将其与事件结合并返回一个EventResponsestuct。

描述该问题的一种非特定场景的方式是“如何Result<Vec<T>, err>从嵌套的 flat_map 中获取Result<Vec<T>, err>,它的嵌套地图为Result<T, err>

下面是我正在使用的代码的抽象/简化版本,它给了我与实际代码相同的错误。

struct Event {
    id: usize,
}

#[derive(Debug)]
struct EventResponse {
    id: usize,
    participants: Vec<i32>,
}

fn main() {
    let orgs = vec![1, 3, 14, 12];

    let events: Result<Vec<EventResponse>, &str> = orgs
        .iter()
        .flat_map::<Result<Vec<EventResponse>, &str>, _>(|org_id| {
            get_events_for(*org_id)
                .map_err(|_| "That Org id does not exist")
                .map(|events| {
                    events
                        .iter()
                        .map::<Result<EventResponse, &str>, _>(|event| {
                            get_event_with_participants(event)
                                .map(|event_response| event_response)
                                .map_err(|_| "Participants for that event were not found")
                        })
                        .collect()
                })
        })
        .collect();
}

fn get_events_for(id: usize) -> Result<Vec<Event>, ()> {
    // pretend we are checking against a database of existing org ids, if the org id does not exist, then return an error
    if id == 3 {
        Ok(vec![Event { id }])
    } else {
        Err(())
    }
}

fn get_event_with_participants(event: &Event) -> Result<EventResponse, ()> {
    //pretend the participants are fetched from a database
    let foundParticipants = true;
    if foundParticipants {
        Ok(EventResponse {
            id: event.id,
            participants: vec![1, 2, 5],
        })
    } else {
        Err(())
    }
}

操场

类型注释将显示每个阶段预期返回的内容。我希望events是类型Result<Vec<EventResponse>, &str>,但我收到 2 个错误:

error[E0277]: a collection of type `std::vec::Vec<EventResponse>` cannot be built from an iterator over elements of type `std::result::Result<EventResponse, &str>`
  --> example.rs:27:26
   |
27 |                         .collect()
   |                          ^^^^^^^ a collection of type `std::vec::Vec<EventResponse>` cannot be built from `std::iter::Iterator<Item=std::result::Result<EventResponse, &str>>`
   |
   = help: the trait `std::iter::FromIterator<std::result::Result<EventResponse, &str>>` is not implemented for `std::vec::Vec<EventResponse>`

error[E0277]: a collection of type `std::result::Result<std::vec::Vec<EventResponse>, &str>` cannot be built from an iterator over elements of type `std::vec::Vec<EventResponse>`
  --> example.rs:30:10
   |
30 |         .collect();
   |          ^^^^^^^ a collection of type `std::result::Result<std::vec::Vec<EventResponse>, &str>` cannot be built from `std::iter::Iterator<Item=std::vec::Vec<EventResponse>>`
   |
   = help: the trait `std::iter::FromIterator<std::vec::Vec<EventResponse>>` is not implemented for `std::result::Result<std::vec::Vec<EventResponse>, &str>`

编辑:无法修改get_events_for功能,但是,如果有帮助,可以修改功能。get_event_with_participants

4

1 回答 1

1

map对这个问题感兴趣,我尝试用and来实现它try_fold。直接使用flat_map对我不起作用,因为我无法绕过第一个内部循环必须产生一个Result. 我将错误消息移到函数中,但是如果您明确想要避免它,可以很容易地撤消它。

struct Event {
    id: usize,
}

#[derive(Debug)]
struct EventResponse {
    id: usize,
    participants: Vec<i32>,
}

fn main() {
    let orgs = vec![1, 3, 14, 12];

    let events: Result<Vec<EventResponse>, &str> = orgs
        .iter()
        .map(|org_id| {
            get_events_for(*org_id)?
                .iter()
                .map(get_event_with_participants)
                .collect::<Result<Vec<_>, _>>()
        })
        .collect::<Result<Vec<_>, _>>()
        .map(|org_responses| org_responses.into_iter().flatten().collect());
}

fn get_events_for(id: usize) -> Result<Vec<Event>, &'static str> {
    // pretend we are checking against a database of existing org ids, if the org id does not exist, then return an error
    if id == 3 {
        Ok(vec![Event { id }])
    } else {
        Err("That Org id does not exist")
    }
}

fn get_event_with_participants(event: &Event) -> Result<EventResponse, &'static str> {
    //pretend the participants are fetched from a database
    let foundParticipants = true;
    if foundParticipants {
        Ok(EventResponse {
            id: event.id,
            participants: vec![1, 2, 5],
        })
    } else {
        Err("Participants for that event were not found")
    }
}

对于try_fold,主要功能将变为:

fn main() {
    let orgs = vec![1, 3, 14, 12];

    let events: Result<Vec<EventResponse>, &str> =
        orgs.iter().try_fold(Vec::new(), |mut responses, &org| {
            responses = get_events_for(org)?
                .into_iter()
                .try_fold(responses, |mut responses, event| {
                    let response = get_event_with_participants(&event)?;
                    responses.push(response);
                    Ok(responses)
                })?;
            Ok(responses)
        });
}

就我个人而言,我是该map版本的粉丝,因为修改Vecusingtry_fold感觉很尴尬,因为尽管直接修改了累加器,但您必须返回累加器Vec

另一个要考虑的版本是只使用循环,在这种情况下看起来要简单得多,因为您可以使用?运算符来处理错误:

fn main() {
    let orgs = vec![1, 3, 14, 12];

    let events = get_all_responses(orgs);
}

fn get_all_responses(
    orgs: impl IntoIterator<Item = usize>,
) -> Result<Vec<EventResponse>, &'static str> {
    let mut responses = Vec::new();
    for org in orgs.into_iter() {
        for event in get_events_for(org)? {
            responses.push(get_event_with_participants(&event)?)
        }
    }
    Ok(responses)
}
于 2019-10-12T18:42:55.150 回答