You quite rightfully assessed that the way you wrote it is not possible, because Rust guarantees memory safety and storing it as a reference would give the possibility to create a dangling pointer.
There are several solutions that I could see here.
Static Strings
This of course only works if you store compile-time static strings.
struct Data {
    selected: &'static str,
    tables: Vec<&'static str>,
}
fn main() {
    let tables = vec!["table1", "table2"];
    let my_stuff = Data {
        selected: &tables[0],
        tables,
    };
}
The reason this works is because static strings are non-mutable and guaranteed to never be deallocated. Also, in case this is confusing, I recommend reading up on the differences between Strings and str slices.
You can even go one further and reduce the lifetime down to 'a. But then, you have to store them as &'a str in the vector, to ensure they cannot be edited.
But that then allows you to store Strings in them, as long as the strings can be borrowed for the entire lifetime of the Data object.
struct Data<'a> {
    selected: &'a str,
    tables: Vec<&'a str>,
}
fn main() {
    let str1 = "table1".to_string();
    let str2 = "table2".to_string();
    let tables = vec![str1.as_str(), str2.as_str()];
    let my_stuff = Data {
        selected: &tables[0],
        tables,
    };
}
Reference counting smart pointers
Depending your situation, there are several types that are recommended:
- Rc<...>- if your data is immutable. Otherwise, you need to create interior mutability with:
- Rc<Cell<...>>- safest and best solution IF your problem is single-threaded and deals with simple data types
- Rc<RefCell<...>>- for more complex data types that have to be updated in-place and can't just be moved in and out
- Arc<Mutex<...>>- as soon as your problem stretches over multiple threads
In your case, the data is in fact simple and your program is single-threaded, so I'd go with:
use std::{cell::Cell, rc::Rc};
struct Data {
    selected: Rc<Cell<String>>,
    tables: Vec<Rc<Cell<String>>>,
}
fn main() {
    let tables = vec![
        Rc::new(Cell::new("table1".to_string())),
        Rc::new(Cell::new("table2".to_string())),
    ];
    let my_stuff = Data {
        selected: tables[0].clone(),
        tables,
    };
}
Of course, if you don't want to modify your strings after creation, you could go with:
use std::rc::Rc;
struct Data {
    selected: Rc<String>,
    tables: Vec<Rc<String>>,
}
fn main() {
    let tables = vec![Rc::new("table1".to_string()), Rc::new("table2".to_string())];
    let my_stuff = Data {
        selected: tables[0].clone(),
        tables,
    };
}
Hiding the data structure and using an index
As you already mentioned, you could use an index instead. Then you would have to hide the vector and provide getters/setters/modifiers to make sure the index is kept in sync when the vector changes.
I'll keep the implementation up to the reader and won't provide an example here :)
I hope this helped already, or at least gave you a couple of new ideas. I'm happy to see new people come to the community, so feel free to ask further questions if you have any :)