文字列を& 'static strに変換する方法


89

どのようにして変換するかString&str?具体的にはstrstaticライフタイム付きの(&'static str)に変換したいと思います。


それは可能でも望ましくもないようです。'staticライフタイムは、文字列が割り当て解除されないこと、つまりメモリリークを意味します。なぜ適切なもの&'static str&'a strはなく、なぜ必要なの'aですか?

3
それを&'a str 当時に変換するとどうなりますか?
クリストフ

経由as_slice。解決しようとしている具体的な問題と、その際に発生する問題について説明しておくと、簡単に助かります。

またSendStr、所有された文字列または静的文字列のいずれかのタイプであることに注意してください。
Chris Morgan

回答:


132

Rust 1.0用に更新

&'static strから取得することはできません。Stringなぜなら、Stringsはプログラムの&'static存続期間全体にわたって存続しない可能性があり、それが存続期間の意味です。String自分のライフタイムでパラメーター化されたスライスのみを取得できます。

a 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強制と呼ばれ&、just 演算子の使用を許可し、コンパイラーは*コンテキストに基づいて適切な量​​のを自動的に挿入します。

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/に固有のものではないことに注意してください。たとえば、/ および/ from モジュールまたは/ from モジュールなど、を&str介して接続されているタイプのすべてのペアで使用できます。DerefCStringCStrOsStringOsStrstd::ffiPathBufPathstd::path


26
Rust 1.10では、代わりにlet s_slice: &str = &s[..];これを行うことができますlet s_slice: &str = s.as_str();
。– Shnatsel

3
場合によっては、元の文字列がmatch {...}ブロックのように十分に機能しないことがあります。それはにつながり's' does not live long enough errorます。
Dereckson 2016

38

あなたはそれを行うことができますが、それはのメモリ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);
}

7
Stringオブジェクトが削除されない限り、メモリは存続することが保証されます。以来mem::forget、オブジェクトが削除されないことを保証し、我々は含まへの参照があることが保証されてstr無効になることはありません。したがって、これは'static参照であると断言できます
oli_obk

1
これは、オリジナルから作成されたトークンをすべてのスレッドで使用できるようStringにa をに強制する必要がある私のRustアプリケーションにとって非常に役立ちました。これがないと、Rustコンパイラーは、メイン関数の最後で終了する存続期間があったと不満を言うでしょう。&'static strStringString'static
mmstick 2016

1
@mmstick:その場合のより良い解決策は、crossbeamスレッドを使用してスコープを指定することです
oli_obk

3
@mmstick:アプリケーション全体をクロスビームスコープに入れて、スコープ外に文字列を作成すると、正確にそれが得られます。
oli_obk 2017年

1
この答えは素晴らしいです!どちらも、静的な文字列スライスを不正に作成する方法を教えてくれ、それを行わないように説得しました!多くの場所で静的文字列スライスを使用しないようにアプリをリファクタリングすることにしました。
Paul Chernoch

21

Rustバージョン1.26以降では、コードを使用せずにa Stringをに変換できます。&'static strunsafe

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はプログラムの全寿命を意味するので、より長い寿命は存在しません。しかし、同等の寿命で十分です。したがってString、の有効期間がの場合、そこから参照を'static取得できます&'static str

staticタイプのの作成はStringconst fn機能がリリースされたときのRust 1.31で理論的に可能になりました。残念ながら、現在、aを返す唯一のconst関数StringString::new()あり、それはまだ機能ゲートの背後にあります(したがって、今のところRust nightlyが必要です)。

したがって、次のコードは望ましい変換(毎晩使用)を実行します...実際、このエッジケースで可能であることを示す完全性を除いて、実際には使用されません。

#![feature(const_string_new)]

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

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

fn main() {
    do_something(&MY_STRING);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.