Как преобразовать строку в статическую строчку & '

92

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

Кристоф
источник
Это не кажется возможным или желательным. 'staticСрок службы будет означать, что строка никогда не будет освобождена, то есть утечка памяти. Зачем он нужен &'static strвместо какого- &'a strто подходящего 'a?
3
Как бы это выглядело, чтобы преобразовать это в &'a str то?
Кристоф
Via as_slice. Было бы легче помочь, если бы вы описали, какую конкретную проблему вы пытаетесь решить и с какими проблемами вы при этом сталкиваетесь.
Также обратите внимание SendStrна тип, который является либо собственной строкой, либо статической строкой.
Крис Морган

Ответы:

134

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

Вы не можете получить &'static strиз a, Stringпотому что Strings может не прожить всю жизнь вашей программы, и именно это &'staticозначает время жизни. Из него можно получить только срез, параметризованный 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 coercion, и он позволяет использовать только &оператор, и компилятор автоматически вставит соответствующее количество *s в зависимости от контекста:

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модуля.

Владимир Матвеев
источник
29
В Rust 1.10 вместо этого let s_slice: &str = &s[..];можно просто сделать это:let s_slice: &str = s.as_str();
Шнацель
3
Иногда исходная строка недостаточно жива, как в блоке match {...}. Это приведет к созданию файла 's' does not live long enough error.
Dereckson
42

Вы можете это сделать, но это связано с утечкой памяти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);
}
oli_obk
источник
8
Stringдает гарантию, что до тех пор, пока объект не был отброшен, память остается активной. Поскольку мы mem::forgetгарантируем, что объект никогда не будет удален, мы гарантируем, что ссылка на содержащийся strникогда не будет недействительной. Таким образом, мы можем утверждать, что это 'staticотсылка
oli_obk
1
Это было невероятно полезно для моего приложения на Rust, которому нужно было Stringпреобразовать a в a, &'static strчтобы токены, созданные из оригинала String, были доступны во всех потоках. Без этого компилятор Rust жаловался бы, что у меня Stringвремя жизни заканчивается в конце основной функции, что было недостаточно, потому что у него не было 'staticгарантии.
mmstick
1
@mmstick: лучшим решением в этом случае будет использование crossbeamпотоков с
ограниченным объемом
3
@mmstick: если вы поместите все свое приложение в область видимости crossbeam и создадите строку вне области видимости, вы получите именно это.
oli_obk
1
Отличный ответ! Он одновременно рассказал мне, как искусно создать статический фрагмент строки, и убедил меня не делать этого! Я решил реорганизовать свое приложение, чтобы не использовать статические строковые фрагменты во многих местах.
Пол Чернох
24

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

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

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

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

Свен Марнах
источник
2

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

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

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

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

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

#![feature(const_string_new)]

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

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

fn main() {
    do_something(&MY_STRING);
}
Заргоны
источник