Armani_bologne
Armani_bologne

Reputation: 81

Iterate, filter and map data from one struct to another in Rust

Struct

pub struct UserAccess {
    pub user: String,
    pub dept: String,
    pub hreflink: String,
}

pub struct RoleMembers {
    pub role: String,
    pub members: Vec<String>,
}


pub struct DepartmentAccess {
    pub department: String,
    pub department_id: String,
    pub role_members: Vec<RoleMembers>,
}

I am trying to filter data in DepartmentAccess struct based on input ('user' & 'department') from UI and need to map 'user', 'departmentid' and a 'reflink' to another struct (UserAccess) which required for UI. But while building it's throwing error as below. What do I need to do here?

Code

  let mut v: Vec<UserAccess> = vec![];
    let access_data = get_access_data();
    let user_data: Vec<UserAccess> = access_data
        .into_iter()
        .filter(|a| a.department == department && a.role_members.iter().any(|b| b.members.contains(&user)))
        .map(|r| {
            v.push(UserAccess {
                user: user,
                dept: r.department_id,
                hreflink: format!("department/{}", r.department_id),
            })
        })
        .collect();

Error

value of type `Vec<UserAccess>` cannot be built from `std::iter::Iterator<Item=()>`
   |
   = help: the trait `FromIterator<()>` is not implemented for `Vec<UserAccess>`

Upvotes: 0

Views: 722

Answers (1)

Masklinn
Masklinn

Reputation: 42292

The error seems clear.

collect() creates a collection of whatever the iterator returns. But here your map callback:

    |r| {
        v.push(UserAccess {
            user: user,
            dept: r.department_id,
            hreflink: format!("department/{}", r.department_id),
        })
    }

returns whatever Vec::push returns, which is () (aka nothing, not to be confused with not returning).

Which is in no way compatible with the Vec<UserAccess> you're requesting.

Why are you both filling a vec and trying to collect to one, at the same time, with the same data, from the same processing pipeline?

Pick one or the other:

  • Either return the UserData from the callback and collect into user_data
  • Or execute the pipeline for its side-effects and fill v by mutation, in which case I would recommend for_each or a regular for loop in order to "pump" the iterator -- iterators are lazy so map will not run anything in and of itself -- as well as show that the final step is side-effecting: map is generally used to perform functional transforms, and at least mostly valued for their result. And collect is not the correct method to run an iterator to completion.

Upvotes: 1

Related Questions