0

I'm new to Rust, and I want to process strings in a function in Rust and then return a struct that contains the results of that processing to use in more functions. This is very simplified and a bit messier because of all my attempts to get this working, but:

struct Strucc<'a> {
    string: &'a str,
    booool: bool
}

fn do_stuff2<'a>(input: &'a str) -> Result<Strucc, &str> {
    let to_split = input.to_lowercase();
    let splitter = to_split.split("/");

    let mut array: Vec<&str> = Vec::new();
    for split in splitter {
        array.push(split);
    }
    
    let var = array[0];
    println!("{}", var);
    let result = Strucc{
        string: array[0],
        booool: false
    };
    Ok(result)
}

The issue is that to convert the &str to lowercase, I have to create a new String that's owned by the function.

As I understand it, the reason this won't compile is because when I split the new String I created, all the &strs I get from it are substrings of the String, which are all still owned by the function, and so when the value is returned and that String goes out of scope, the value in the struct I returned gets erased.

I tried to fix this with lifetimes (as you can see in the function definition), but from what I can tell I'd have to give the String a lifetime which I can't do as far as I'm aware because it isn't borrowed. Either that or I need to make the struct own that String (which I also don't understand how to do, nor does it seem reasonable as I'd have to make the struct mutable).

Also as a sidenote: Previously I have tried to just use a String in the struct but I want to define constants which won't work with that, and I still don't think it would solve the issue. I've also tried to use .clone() in various places just in case but had no luck (though I know why this shouldn't work anyway).

I have been looking for some solution for this for hours and it feels like such a small step so I feel I may be asking the wrong questions or have missed something simple but please explain it like I'm five because I'm very confused.

Aurillium
  • 3
  • 1
  • 1
    You could use a String in your struct and keep the string slice as an input in your function (or create a generic type parameter that can accept both), it would simplify your life, wouldn't it be acceptable ? – Peterrabbit Oct 22 '22 at 07:36
  • @Peterrabbit It would definitely help with the current issue, but I wouldn't be able to define constants and I guess the perfectionist in me just doesn't like that every time the function is called, several variables that are the same every time would have to be created. It just feels like there should be a simpler way to do that – Aurillium Oct 22 '22 at 07:44
  • Then maybe try define your string slice field with a static lifetime: `&'static str` – Peterrabbit Oct 22 '22 at 08:19
  • But since you are mutating the input and creating a new slice I think you are going to have problem anyway referencing a slice created inside a function, it can't respect the static lifetime requirement. – Peterrabbit Oct 22 '22 at 08:21
  • @Peterrabbit Yeppp. Also am I right in saying if you don't need that struct for the entire duration of the program, don't use `&'static`? Because from what I can tell that keeps that object for the entire duration of the program even after it isn't needed anymore which can lead to memory leaks but I can see how it would be a tempting path. – Aurillium Oct 23 '22 at 04:13
  • The fact that your struct references something with a static lifetime doesn't necessarily mean that the struct has also a static lifetime, it just mean that the struct can't outlive the data it references. But anyway, the pattern you are trying to implement is impossible to make working. As said in the answer given, since you are splitting the input, the str you reference in the returned value can't outlive the scope of the function so you must own the string. – Peterrabbit Oct 23 '22 at 06:38

1 Answers1

2

I think you misunderstand what &str actually is. &str is just a pointer to the string data plus a length. The point of &str is to be an immutable reference to a specific string, which enables all sorts of nice optimizations. When you attempt to turn the &str lowercase, Rust needs somewhere to put the data, and the only place to put it would be a String, because Strings own their data. Take a look at this post for more information.

Your goal is unachievable without Strucc containing a String, since .to_lowercase() has to create new data, and you have to allocate the resulting data somewhere in order to own a reference to it. The best place to put the resulting data would be the returned struct, i.e. Strucc, and therefore Strucc must contain a String.

Also as a sidenote: Previously I have tried to just use a String in the struct but I want to define constants which won't work with that, and I still don't think it would solve the issue.

You can use "x".to_owned() to create a String literal.

If you're trying to create a global constant, look at once_cell's lazy global initialization.

virchau13
  • 1,175
  • 7
  • 19