Search code examples
vectorrustvisibilityprivatemap-function

How to convert Vec<Item> to Vec<String>?


I have the following object, and trying to convert Vec<Courses> and retrieve CourseName.

pub struct Schools {
    pub courses: Vec<CourseName>,
}

pub struct CourseName(String);

impl CourseName {
    pub fn as_str(&self) -> &str {
        &self.0[..]
    }
}

Trying to get the Vec<String>, but my following approach does not work,

assigned_courses:Vec<String> = courses.iter().map(|c| c.clone().as_str()).collect()

getting the following error:

value of type `Vec<std::string::String>` cannot be built from `std::iter::Iterator<Item=&str>`

Update:

enter image description here


Solution

  • The map closure receives a &CourseName so clone just copies the reference. What you instead want is to access the tuple and clone the inner String with c.0.

    let assigned_courses: Vec<String> = courses.iter().map(|c| c.0.clone()).collect();
    

    Alternatively, if references to the course names are enough, then instead you can use as_str on the inner String.

    let assigned_courses: Vec<&str> = schools.courses.iter().map(|c| c.0.as_str()).collect();
    

    To fix the "private field" error. You can add a visibility modifier, e.g.

    pub struct CourseName(pub String);
    

    However, it's probably better to keep it as private, and instead add a method like as_str().

    impl CourseName {
        pub fn as_str(&self) -> &str {
            &self.0
        }
    }
    

    Then resulting in:

    let assigned_courses: Vec<String> = schools.courses.iter().map(|c| c.as_str().to_string()).collect();
    

    Alternatively, you could also impl AsRef<str> and/or Display for CourseName, to make everything more generalized.


    Assuming that CourseName is just to have a typed version instead of a String. Then you could instead impl Display for CourseName.

    use std::fmt;
    
    pub struct CourseName(String);
    
    impl fmt::Display for CourseName {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.0)
        }
    }
    

    This allows you to do println!("{}, course") along with course.to_string().

    let assigned_courses: Vec<String> = schools.courses.iter().map(|c| c.to_string()).collect();