Bagaimana mengubah String menjadi & 'str statis

92

Bagaimana cara mengubah a Stringmenjadi a &str? Lebih khusus lagi, saya ingin mengubahnya menjadi strdengan masa statichidup ( &'static str).

Christoph
sumber
Itu sepertinya tidak mungkin atau diinginkan. 'staticmasa hidup akan menyiratkan bahwa string tidak pernah dibatalkan alokasinya, yaitu kebocoran memori. Mengapa Anda membutuhkan, &'static strbukan &'a struntuk beberapa yang sesuai 'a?
3
Bagaimana rasanya mengubahnya menjadi &'a str itu?
Christoph
Melalui as_slice. Akan lebih mudah membantu jika Anda menjelaskan masalah konkret apa yang ingin Anda selesaikan dan masalah apa yang Anda hadapi saat melakukannya.
Perhatikan juga SendStr, tipe yang merupakan string yang dimiliki atau string statis.
Chris Morgan

Jawaban:

135

Diperbarui untuk Rust 1.0

Anda tidak dapat memperoleh &'static strdari Stringkarena Strings tidak mungkin hidup untuk seluruh kehidupan dari program Anda, dan bahwa ini apa &'staticberarti seumur hidup. Anda hanya bisa mendapatkan potongan yang diparameterisasi menurut Stringmasa hidupnya.

Untuk beralih dari a Stringke slice, &'a strAnda dapat menggunakan sintaks slicing:

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

Atau, Anda dapat menggunakan fakta yang Stringmengimplementasikan Deref<Target=str>dan melakukan peminjaman kembali secara eksplisit:

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

Bahkan ada cara lain yang memungkinkan sintaks yang lebih ringkas tetapi hanya dapat digunakan jika kompiler dapat menentukan tipe target yang diinginkan (misalnya dalam argumen fungsi atau binding variabel yang diketik secara eksplisit). Ini disebut paksaan deref dan memungkinkan menggunakan &operator saja , dan kompilator akan secara otomatis memasukkan jumlah yang sesuai *berdasarkan konteks:

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

Perhatikan bahwa pola ini tidak unik untuk String/ &str- Anda dapat menggunakannya dengan setiap pasangan tipe yang dihubungkan Deref, misalnya, dengan CString/ CStrdan OsString/ OsStrdari std::ffimodul atau PathBuf/ Pathdari std::pathmodul.

Vladimir Matveev
sumber
29
Di Rust 1.10 alih-alih let s_slice: &str = &s[..];Anda cukup melakukan ini:let s_slice: &str = s.as_str();
Shnatsel
3
Kadang-kadang, string asli tidak cukup hidup, seperti di blok pertandingan {...}. Itu akan menyebabkan a 's' does not live long enough error.
Dereckson
42

Anda dapat melakukannya, tetapi ini melibatkan kebocoran memori fileString . Ini bukanlah sesuatu yang harus Anda lakukan dengan mudah. Dengan membocorkan memori tersebut String, kami menjamin bahwa memori tersebut tidak akan pernah bisa dibebaskan (demikian pula kebocorannya). Oleh karena itu, setiap referensi ke objek dalam dapat diartikan sebagai memiliki masa 'statichidup.

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
sumber
8
Stringmembuat jaminan, bahwa selama objek tersebut belum dijatuhkan, memori tetap hidup. Karena mem::forgetjaminan bahwa objek tidak akan pernah dijatuhkan, kami dijamin bahwa referensi ke konten strtidak akan pernah valid. Jadi kami dapat menegaskan bahwa ini adalah 'staticreferensi
oli_obk
1
Ini sangat membantu untuk aplikasi Rust saya, yang diperlukan untuk memaksa sebuah Stringke &'static strsehingga token dibuat dari aslinya Stringakan tersedia di semua thread. Tanpa ini, kompilator Rust akan mengeluh bahwa Stringmasa pakai saya berakhir pada akhir fungsi utama, yang tidak cukup baik karena tidak memiliki 'staticjaminan.
mmstick
1
@mmstick: solusi yang lebih baik dalam hal ini adalah menggunakan crossbeamdan
cakupan
3
@mmstick: jika Anda meletakkan seluruh aplikasi Anda ke dalam lingkup crossbeam dan membuat string di luar lingkup, Anda akan mendapatkan itu.
oli_obk
1
Jawaban ini bagus! Keduanya memberi tahu saya cara dengan licik membuat potongan string statis dan meyakinkan saya untuk tidak melakukannya! Saya memilih untuk merefaktor aplikasi saya agar tidak menggunakan potongan string statis di banyak tempat.
Paul Chernoch
24

Pada Rust versi 1,26, adalah mungkin untuk mengkonversi Stringke &'static strtanpa menggunakan unsafekode:

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

Ini mengubah Stringcontoh menjadi sebuah kotakstr dan segera membocorkannya. Ini membebaskan semua kapasitas berlebih yang mungkin ditempati string saat ini.

Perhatikan bahwa hampir selalu ada solusi yang lebih disukai daripada objek bocor, misalnya menggunakan crossbeampeti jika Anda ingin berbagi status antar utas.

Sven Marnach
sumber
2

TL; DR: Anda bisa mendapatkan a &'static strdari Stringyang memiliki file'static seumur hidup.

Meskipun jawaban lain benar dan paling berguna, ada kasus tepi (tidak terlalu berguna), di mana Anda memang dapat mengonversi a Stringke a&'static str :

Umur referensi harus selalu lebih pendek atau sama dengan umur objek yang direferensikan. Yaitu objek yang direferensikan harus hidup lebih lama (atau sama panjang) dari referensi. Karena 'staticberarti seluruh masa program, masa hidup yang lebih lama tidak ada. Tapi masa hidup yang sama sudah cukup. Jadi, jika Stringseumur hidup 'static, Anda bisa mendapatkan file&'static str referensi darinya.

Membuat statictipe Stringsecara teoritis menjadi mungkin dengan Rust 1.31 ketika const fnfitur itu dirilis. Sayangnya, satu-satunya fungsi const yang mengembalikan a StringisString::new() saat, dan itu masih di belakang gerbang fitur (sehingga Rust malam diperlukan untuk saat ini).

Jadi kode berikut melakukan konversi yang diinginkan (menggunakan nightly) ... dan sebenarnya tidak memiliki penggunaan praktis kecuali untuk kelengkapan menunjukkan bahwa itu mungkin dalam kasus tepi ini.

#![feature(const_string_new)]

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

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

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