String lifetime issues

Hello,
I am working on a system which does some operations and creates a large output string. This output string often contains the same strings, so I am trying to store references to those smaller strings to avoid cloning them.
I have created a small playground example which shows the basic problem. It contains an enum Command which stores string references of a SnippetHolder struct. Additionally There is a Main struct which holds both the SnippetHolder and a vec of commands with references to this snippet holder. I know this should be avoided, but I have no clue how else this could be implemented.
Playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=50750beb0fe097206a736ffaccb87a1e

That's a self-referential type, which is not currently possible in safe Rust.

Either separate the owning container from the references (i.e. put them in separate structs), or substitute the &strs with Range<usize> and compute the slices on-the-fly (playground).


Note furthermore that &'a mut self is almost never what you want. It forces the borrow of self to last as long as whatever the lifetime parameter is substituted with, which is necessarily longer than just the method call itself, which in turn is why you get the error that main is still borrowed even after the call.

A key thing to remember is that tagging a struct with a lifetime (<'a>) only works when that data is stored outside the struct somewhere— Anytime you write &'a mut Something<'a> you’re going to have trouble.

There’s a few ways around this for your code:

  • If all the snippets are literals, you can store them as &'static str’s instead of Strings. (playground)
  • If they’re dynamically generated, you can use Rc<str> (playground)
  • You can move the SnippetHolder into a local variable of main (playground)
1 Like

I see now why this does not work, in my case it is probably the best solution to use Rc.
Thank you both so much for your answers!