Newbie: lifetime & borrowing String and &str in a struct

I'd like to figure out how to get this to work:

struct Input<'a>{
  words: Vec<&'a str>,
  normalized: String,
}

impl Input<'_> {
    fn new(str : &str) -> Input{
        let normalized : String = str.chars().filter(|c| c.is_alphanumeric()).collect();
        let words : Vec<&str> = normalized.split_whitespace().collect();
        
        Input{
            words: words,
            normalized: normalized,
        }
    }
}

fn main() {
    Input::new("Hello, world!");
}

I know I could turn words into a Vec<String> and avoid all of this, but I feel that it must be possible to have words be a Vec<&str> generated from normalized.

I think I have two problems. First is about lifetime. I need to tell the compiler that words and normalized share the same liftetime.

The other is about borrowing. words borrows normalized which, I think, makes it impossible for me move to my struct and return from the function.

Even if those observations are right, I have no idea how to fix it.

This is not possible. Structs may not contain references that point into the struct itself. References must point to values outside the struct. For example, you could do this:

struct Normalized {
    normalized: String,
}

impl Normalized {
    fn new(str: &str) -> Self {
        Self {
            normalized: str.chars().filter(|c| c.is_alphanumeric()).collect(),
        }
    }
}

struct Input<'a> {
    words: Vec<&'a str>,
}

impl<'a> Input<'a> {
    fn new(str: &'a Normalized) -> Input {
        let words: Vec<&str> = str.normalized.split_whitespace().collect();

        Input { words: words }
    }
}

fn main() {
    let norm = Normalized::new("Hello, world!");
    Input::new(&norm);
}
3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.