Как преобразовать строку в & 'static str

Как мне преобразовать String в &str? Более конкретно, я хотел бы преобразовать его в str со static временем жизни (&'static str).

Ответ 1

Обновлено для Rust 1.0

Вы не можете получить &'static str из String, потому что String не проживает всю жизнь вашей программы и что означает &'static lifetime. Вы можете получить только срез, параметризованный String собственным временем жизни от него.

Чтобы перейти от String к фрагменту &'a str, вы можете использовать синтаксис разрезания:

let s: String = "abcdefg".to_owned();
let s_slice: &str = &s[..];  // take a full slice of the string

В качестве альтернативы вы можете использовать тот факт, что String реализует Deref<Target=str> и выполняет явное переопределение:

let s_slice: &str = &*s;  // s  : String 
                          // *s : str (via Deref<Target=str>)
                          // &*s: &str

Существует еще один способ, который позволяет использовать еще более сжатый синтаксис, но его можно использовать только в том случае, если компилятор может определить желаемый тип целевого объекта (например, в аргументах функции или явно введенных переменных). Он называется принуждением deref и позволяет использовать только оператор &, и компилятор автоматически вставляет соответствующее количество * в зависимости от контекста:

let s_slice: &str = &s;  // okay

fn take_name(name: &str) { ... }
take_name(&s);           // okay as well

let not_correct = &s;    // this will give &String, not &str,
                         // because the compiler does not know
                         // that you want a &str

Обратите внимание, что этот шаблон не уникален для String/&str - вы можете использовать его с каждой парой типов, которые связаны через Deref, например, с помощью CString/CStr и OsString/OsStr из std::ffi или PathBuf/Path из std::path.

Ответ 2

Вы можете сделать это, но это включает в себя утечку памяти String. Это не то, что вы должны делать слегка. Утечка памяти String гарантирует, что память никогда не будет освобождена (таким образом, утечка). Поэтому любые ссылки на внутренний объект могут быть интерпретированы как имеющие 'static время жизни".

fn string_to_static_str(s: String) -> &'static str {
    Box::leak(s.into_boxed_str())
}

fn main() {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).unwrap();
    let s: &'static str = string_to_static_str(s);
}

Ответ 3

Начиная с версии Rust 1.26, можно преобразовать String в &'static str String без использования unsafe кода:

fn string_to_static_str(s: String) -> &'static str {
    Box::leak(s.into_boxed_str())
}

Это преобразует экземпляр String в упакованный str и сразу же пропускает его. Это освобождает всю избыточную емкость, которую строка может занимать в настоящее время.

Обратите внимание, что почти всегда есть решения, которые предпочтительнее протекающих объектов, например, использование ящика с crossbeam балкой, если вы хотите разделить состояние между потоками.

Ответ 4

TL; DR: вы можете получить &'static str String из String которая сама имеет 'static время жизни.

Хотя другие ответы верны и наиболее полезны, есть (не очень полезный) край, в котором вы действительно можете преобразовать String в &'static str:

Время жизни ссылки всегда должно быть короче или равно времени жизни ссылочного объекта. Т.е. указанный объект должен жить дольше (или равным долго), чем ссылка. Так как 'static означает всю жизнь программы, более длинная жизнь не существует. Но равного времени жизни будет достаточно. Таким образом, если у String есть время жизни 'static, вы можете получить ссылку &'static str.

Создание static типа String теоретически стало возможным с Rust 1.31, когда была выпущена функция const fn. К сожалению, единственной константной функцией, возвращающей String является String::new(), и она все еще за функциональными воротами (так что сейчас требуется ночная обработка Rust).

Таким образом, следующий код выполняет желаемое преобразование (используя ночной режим)... и фактически не имеет практического применения, за исключением полноты показа, что это возможно в этом крайнем случае.

#![feature(const_string_new)]

static MY_STRING: String = String::new();

fn do_something(_: &'static str) {
    // ...
}

fn main() {
    do_something(&MY_STRING);
}