Rumah >Peranti teknologi >industri IT >Cara menggunakan pembolehubah global secara idiomatically dalam karat

Cara menggunakan pembolehubah global secara idiomatically dalam karat

Jennifer Aniston
Jennifer Anistonasal
2025-02-10 15:53:09701semak imbas

Cara menggunakan pembolehubah global secara idiomatically dalam karat

Mengisytiharkan dan menggunakan pembolehubah global dalam karat boleh menjadi rumit. Biasanya untuk bahasa ini, karat memastikan keteguhan dengan memaksa kita menjadi sangat jelas.

Dalam artikel ini, saya akan membincangkan perangkap yang dikompilasi karat ingin menyelamatkan kita dari. Kemudian saya akan menunjukkan kepada anda penyelesaian terbaik untuk senario yang berbeza.

Takeaways Key

    Gunakan `static` atau` const` untuk mengisytiharkan pembolehubah global dalam karat, kerana `let` tidak dibenarkan pada skop global.
  • Untuk inisialisasi runtime yang selamat dari pembolehubah global, pertimbangkan untuk menggunakan `std :: sync :: sekali` atau perpustakaan luaran seperti` Lazy_static` atau `once_cell`.
  • Elakkan menggunakan `statik mut` secara langsung disebabkan oleh masalah keselamatan yang berpotensi; Sebaliknya, bungkus akses dalam blok `tidak selamat 'atau gunakan primitif penyegerakan seperti mutexes.
  • Untuk aplikasi tunggal, `thread_local!` Makro dapat menyediakan cara yang selamat untuk mengendalikan keadaan global tanpa memerlukan penyegerakan.
  • pembolehubah global refactor ke dalam skop tempatan di mana mungkin, menggunakan penunjuk pintar seperti `ARC` untuk pemilikan bersama dan keselamatan benang.
  • Memahami perbezaan antara `const` dan` static` dalam karat: `const` pembolehubah digariskan dan tidak berubah, manakala pembolehubah` statik` boleh mempunyai keadaan yang boleh berubah dengan pilihan mutabiliti dalaman seperti jenis atom atau mutexes.
  • Gambaran Keseluruhan

Terdapat banyak pilihan untuk melaksanakan negara global dalam karat. Sekiranya anda tergesa -gesa, inilah gambaran ringkas mengenai cadangan saya.

anda boleh melompat ke bahagian tertentu artikel ini melalui pautan berikut: Cara menggunakan pembolehubah global secara idiomatically dalam karat

No Globals: Refactor ke Arc / Rc

    Global Inisialisasi Masa Kompilasi: Const T / Static t
  • Gunakan perpustakaan luaran untuk runtime yang mudah dimulakan globals: malas_static / once_cell
  • Melaksanakan inisialisasi runtime anda sendiri: std :: sync :: Setelah statik mut t
  • Kes Khusus untuk Inisialisasi Runtime Single-Threaded: Thread_local
  • percubaan pertama naif menggunakan pembolehubah global dalam karat
mari kita mulakan dengan contoh bagaimana tidak menggunakan pembolehubah global. Anggapkan saya mahu menyimpan masa permulaan program dalam rentetan global. Kemudian, saya ingin mengakses nilai dari pelbagai benang.

pemula karat mungkin tergoda untuk mengisytiharkan pembolehubah global sama seperti pembolehubah lain dalam karat, menggunakan LET. Program penuh kemudian dapat kelihatan seperti ini:

cubalah untuk diri sendiri di taman permainan!

Ini adalah sintaks tidak sah untuk karat. Kata kunci biarkan tidak boleh digunakan dalam skop global. Kita hanya boleh menggunakan statik atau const. Yang terakhir mengisytiharkan pemalar yang benar, bukan pemboleh ubah. Hanya statik memberi kita pemboleh ubah global.

alasan di sebalik ini adalah yang membolehkan peruntukan pembolehubah pada timbunan, semasa runtime. Perhatikan bahawa ini tetap berlaku apabila memperuntukkan timbunan, seperti dalam let t = box :: new ();. Dalam kod mesin yang dihasilkan, masih terdapat penunjuk ke dalam timbunan yang disimpan di timbunan.

Pembolehubah global disimpan dalam segmen data program. Mereka mempunyai alamat tetap yang tidak berubah semasa pelaksanaan. Oleh itu, segmen kod boleh termasuk alamat tetap dan tidak memerlukan ruang pada timbunan sama sekali.

Baiklah, jadi kita dapat memahami mengapa kita memerlukan sintaks yang berbeza. Karat, sebagai bahasa pengaturcaraan sistem moden, ingin menjadi sangat jelas mengenai pengurusan ingatan.

mari kita cuba lagi dengan statik:

<span>use chrono<span>::</span>Utc;
</span>
<span>let START_TIME = Utc::now().to_string();
</span>
<span>pub fn main() {
</span>    <span>let thread_1 = std<span>::thread::</span>spawn(<span>||</span>{
</span>        <span>println!("Started {}, called thread 1 {}", START_TIME.as_ref().unwrap(), Utc::now());
</span>    <span>});
</span>    <span>let thread_2 = std<span>::thread::</span>spawn(<span>||</span>{
</span>        <span>println!("Started {}, called thread 2 {}", START_TIME.as_ref().unwrap(), Utc::now());
</span>    <span>});
</span>
    <span>// Join threads and panic on error to show what went wrong
</span>    thread_1<span>.join().unwrap();
</span>    thread_2<span>.join().unwrap();
</span><span>}
</span>

pengkompil tidak gembira, namun:

<span>use chrono<span>::</span>Utc;
</span>
<span>static START_TIME: String = Utc::now().to_string();
</span>
<span>pub fn main() {
</span>    <span>// ...
</span><span>}
</span>

HM, jadi nilai permulaan pembolehubah statik tidak dapat dikira pada masa runtime. Maka mungkin biarkan ia tidak dikenali?

error<span>[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
</span> <span>--> src/main.rs:3:24
</span>  <span>|
</span><span>3 | static start: String = Utc::now().to_string();
</span>  <span>|                        ^^^^^^^^^^^^^^^^^^^^^^
</span>

ini menghasilkan ralat baru:

<span>use chrono<span>::</span>Utc;
</span>
<span>static START_TIME;
</span>
<span>pub fn main() {
</span>    <span>// ...
</span><span>}
</span>

Jadi itu tidak berfungsi sama ada! Semua nilai statik mesti dimulakan sepenuhnya dan sah sebelum mana -mana kod pengguna dijalankan.

Jika anda datang ke karat dari bahasa lain, seperti JavaScript atau Python, ini mungkin kelihatan tidak perlu. Tetapi mana -mana guru C boleh menceritakan kisah tentang kegagalan perintah permulaan statik, yang boleh membawa kepada perintah permulaan yang tidak ditentukan jika kita tidak berhati -hati.

Contohnya, bayangkan sesuatu seperti ini:

<span>Compiling playground v0.0.1 (/playground)
</span>error<span>: free static item without body
</span> <span>--> src/main.rs:21:1
</span>  <span>|
</span><span>3 | static START_TIME;
</span>  <span>| ^^^^^^^^^^^^^^^^^-
</span>  <span>|                  |
</span>  <span>|                  help: provide a definition for the static: `= <expr>;`
</span>
Dalam coretan kod ini, tidak ada perintah permulaan yang selamat, disebabkan oleh kebergantungan bulat.

Jika ia adalah C, yang tidak peduli dengan keselamatan, hasilnya ialah: 1 b: 1 c: 2. dalam setiap unit kompilasi.

Sekurang -kurangnya ia ditakrifkan apa hasilnya. Walau bagaimanapun, "Fiasco" bermula apabila pembolehubah statik adalah dari fail .cpp yang berbeza, dan oleh itu unit kompilasi yang berbeza. Kemudian pesanan tidak ditentukan dan biasanya bergantung pada susunan fail dalam baris perintah kompilasi.

Dalam karat, sifar-initializing bukanlah sesuatu. Lagipun, sifar adalah nilai yang tidak sah untuk pelbagai jenis, seperti kotak. Selain itu, dalam karat, kami tidak menerima isu pesanan pelik. Selagi kita menjauhkan diri dari yang tidak selamat, pengkompil hanya boleh membenarkan kita menulis kod yang waras. Dan itulah sebabnya pengkompil menghalang kita daripada menggunakan inisialisasi runtime yang mudah. ​​

Tetapi bolehkah saya mengelakkan permulaan dengan menggunakan tiada, bersamaan dengan penunjuk null? Sekurang -kurangnya ini semua sesuai dengan sistem jenis karat. Tentunya saya hanya dapat menggerakkan permulaan ke bahagian atas fungsi utama, kan?

<span>use chrono<span>::</span>Utc;
</span>
<span>let START_TIME = Utc::now().to_string();
</span>
<span>pub fn main() {
</span>    <span>let thread_1 = std<span>::thread::</span>spawn(<span>||</span>{
</span>        <span>println!("Started {}, called thread 1 {}", START_TIME.as_ref().unwrap(), Utc::now());
</span>    <span>});
</span>    <span>let thread_2 = std<span>::thread::</span>spawn(<span>||</span>{
</span>        <span>println!("Started {}, called thread 2 {}", START_TIME.as_ref().unwrap(), Utc::now());
</span>    <span>});
</span>
    <span>// Join threads and panic on error to show what went wrong
</span>    thread_1<span>.join().unwrap();
</span>    thread_2<span>.join().unwrap();
</span><span>}
</span>

ah, baik, ralat yang kita dapat ialah ...

<span>use chrono<span>::</span>Utc;
</span>
<span>static START_TIME: String = Utc::now().to_string();
</span>
<span>pub fn main() {
</span>    <span>// ...
</span><span>}
</span>

Pada ketika ini, saya boleh membungkusnya dalam blok {...} yang tidak selamat dan ia akan berfungsi. Kadang -kadang, ini adalah strategi yang sah. Mungkin untuk menguji jika baki kod berfungsi seperti yang diharapkan. Tetapi ia bukan penyelesaian idiomatik yang saya ingin tunjukkan kepada anda. Oleh itu, mari kita meneroka penyelesaian yang dijamin selamat oleh pengkompil.

Refactor Contoh

Anda mungkin sudah menyedari bahawa contoh ini tidak memerlukan pembolehubah global sama sekali. Dan lebih kerap daripada tidak, jika kita dapat memikirkan penyelesaian tanpa pembolehubah global, kita harus mengelakkannya.

Idea di sini adalah untuk meletakkan perisytiharan di dalam fungsi utama:

error<span>[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
</span> <span>--> src/main.rs:3:24
</span>  <span>|
</span><span>3 | static start: String = Utc::now().to_string();
</span>  <span>|                        ^^^^^^^^^^^^^^^^^^^^^^
</span>

Satu-satunya masalah ialah Peminjam-Checker:

<span>use chrono<span>::</span>Utc;
</span>
<span>static START_TIME;
</span>
<span>pub fn main() {
</span>    <span>// ...
</span><span>}
</span>

Kesalahan ini tidak betul -betul jelas. Pengkompil memberitahu kita bahawa benang yang dilahirkan boleh hidup lebih lama daripada nilai start_time, yang tinggal di bingkai timbunan fungsi utama.

Secara teknikal, kita dapat melihat bahawa ini adalah mustahil. Benang disatukan, oleh itu benang utama tidak akan keluar sebelum benang kanak -kanak selesai.

Tetapi pengkompil tidak cukup pintar untuk mengetahui kes ini. Secara umum, apabila benang baru dilahirkan, penutupan yang disediakan hanya boleh meminjam item dengan hayat statik. Dalam erti kata lain, nilai yang dipinjam mesti hidup untuk jangka hayat program penuh.

Bagi sesiapa sahaja yang belajar tentang karat, ini boleh menjadi titik di mana anda ingin menjangkau pembolehubah global. Tetapi terdapat sekurang -kurangnya dua penyelesaian yang lebih mudah daripada itu. Yang paling mudah adalah untuk mengklonkan nilai rentetan dan kemudian menggerakkan pemilikan rentetan ke dalam penutupan. Sudah tentu, itu memerlukan peruntukan tambahan dan memori tambahan. Tetapi dalam kes ini, ia hanya rentetan pendek dan tiada prestasi kritikal.

Tetapi bagaimana jika ia adalah objek yang lebih besar untuk dikongsi? Sekiranya anda tidak mahu mengklonkannya, bungkusnya di belakang penunjuk pintar yang dikira rujukan. RC adalah jenis yang dikira rujukan tunggal. ARC adalah versi atom yang selamat berkongsi nilai antara benang.

Jadi, untuk memuaskan pengkompil, kita boleh menggunakan arka seperti berikut:

<span>use chrono<span>::</span>Utc;
</span>
<span>let START_TIME = Utc::now().to_string();
</span>
<span>pub fn main() {
</span>    <span>let thread_1 = std<span>::thread::</span>spawn(<span>||</span>{
</span>        <span>println!("Started {}, called thread 1 {}", START_TIME.as_ref().unwrap(), Utc::now());
</span>    <span>});
</span>    <span>let thread_2 = std<span>::thread::</span>spawn(<span>||</span>{
</span>        <span>println!("Started {}, called thread 2 {}", START_TIME.as_ref().unwrap(), Utc::now());
</span>    <span>});
</span>
    <span>// Join threads and panic on error to show what went wrong
</span>    thread_1<span>.join().unwrap();
</span>    thread_2<span>.join().unwrap();
</span><span>}
</span>

cubalah untuk diri sendiri di taman permainan!

Ini telah menjadi rundown cepat mengenai cara berkongsi keadaan di antara benang sambil mengelakkan pembolehubah global. Di luar apa yang saya tunjukkan kepada anda setakat ini, anda mungkin juga memerlukan mutabiliti dalaman untuk mengubah keadaan bersama. Liputan penuh mutabiliti dalaman adalah di luar skop artikel ini. Tetapi dalam contoh ini, saya akan memilih arka > untuk menambah mutabiliti dalaman yang selamat untuk start_time.

Apabila nilai pembolehubah global diketahui pada masa kompilasi

Dalam pengalaman saya, kes penggunaan yang paling biasa untuk keadaan global bukan pembolehubah tetapi pemalar. Dalam karat, mereka datang dalam dua perisa:

  • nilai malar, ditakrifkan dengan const. Ini digariskan oleh pengkompil. Mutabiliti dalaman tidak pernah dibenarkan.
  • Pembolehubah statik, ditakrifkan dengan statik. Mereka menerima ruang tetap dalam segmen data. Mutabiliti dalaman mungkin.

Kedua-duanya boleh dimulakan dengan pemalar masa kompilasi. Ini boleh menjadi nilai mudah, seperti 42 atau "Hello World". Atau ia boleh menjadi ungkapan yang melibatkan beberapa pemalar dan fungsi kompilasi masa yang ditandakan sebagai Const. Selagi kita mengelakkan kebergantungan bulat. (Anda boleh mendapatkan lebih banyak maklumat mengenai ekspresi berterusan dalam rujukan karat.)

<span>use chrono<span>::</span>Utc;
</span>
<span>static START_TIME: String = Utc::now().to_string();
</span>
<span>pub fn main() {
</span>    <span>// ...
</span><span>}
</span>

Biasanya, const adalah pilihan yang lebih baik - melainkan jika anda memerlukan mutabiliti dalaman, atau anda secara khusus ingin mengelakkan inlining.

Sekiranya anda memerlukan mutabiliti dalaman, terdapat beberapa pilihan. Bagi kebanyakan primitif, terdapat varian atom yang sama yang terdapat dalam STD :: Sync :: Atomic. Mereka menyediakan API yang bersih untuk memuat, menyimpan, dan mengemas kini nilai secara atom.

Dalam ketiadaan atom, pilihan biasa adalah kunci. Perpustakaan standard Rust menawarkan kunci baca-tulis (RWLOCK) dan Kunci Pengecualian Bersama (MUTEX).

Walau bagaimanapun, jika anda perlu mengira nilai pada runtime, atau memerlukan peruntukan timbunan, maka const dan statik tidak membantu.

pembolehubah global tunggal yang dibaca dalam karat dengan inisialisasi runtime

Kebanyakan aplikasi yang saya tulis hanya mempunyai satu benang. Dalam hal ini, mekanisme penguncian tidak diperlukan.

Walau bagaimanapun, kita tidak boleh menggunakan statik mut secara langsung dan membungkus akses dalam tidak selamat, hanya kerana hanya ada satu benang. Dengan cara ini, kita boleh berakhir dengan rasuah ingatan yang serius.

Sebagai contoh, meminjam tidak selamat dari pembolehubah global dapat memberi kita banyak rujukan yang boleh dimainkan secara serentak. Kemudian kita boleh menggunakan salah satu daripada mereka untuk melangkah ke atas vektor dan satu lagi untuk mengeluarkan nilai dari vektor yang sama. Iterator kemudiannya boleh melampaui sempadan memori yang sah, kemalangan yang berpotensi yang karat selamat akan dicegah.

tetapi perpustakaan standard mempunyai cara untuk "global" menyimpan nilai untuk akses selamat dalam satu thread. Saya bercakap mengenai penduduk tempatan. Di hadapan banyak benang, setiap benang mendapat salinan bebas pembolehubah. Tetapi dalam kes kita, dengan satu benang, hanya ada satu salinan.

penduduk tempatan dicipta dengan thread_local! Makro. Mengaksesnya memerlukan penggunaan penutupan, seperti yang ditunjukkan dalam contoh berikut:

<span>use chrono<span>::</span>Utc;
</span>
<span>let START_TIME = Utc::now().to_string();
</span>
<span>pub fn main() {
</span>    <span>let thread_1 = std<span>::thread::</span>spawn(<span>||</span>{
</span>        <span>println!("Started {}, called thread 1 {}", START_TIME.as_ref().unwrap(), Utc::now());
</span>    <span>});
</span>    <span>let thread_2 = std<span>::thread::</span>spawn(<span>||</span>{
</span>        <span>println!("Started {}, called thread 2 {}", START_TIME.as_ref().unwrap(), Utc::now());
</span>    <span>});
</span>
    <span>// Join threads and panic on error to show what went wrong
</span>    thread_1<span>.join().unwrap();
</span>    thread_2<span>.join().unwrap();
</span><span>}
</span>
Bukan yang paling mudah dari semua penyelesaian. Tetapi ia membolehkan kita melakukan kod inisialisasi sewenang -wenangnya, yang akan berjalan tepat pada waktunya apabila akses pertama ke nilai berlaku.

thread-thread adalah sangat baik ketika datang ke mutabilitas dalaman. Tidak seperti semua penyelesaian lain, ia tidak memerlukan penyegerakan. Ini membolehkan menggunakan refcell untuk mutabiliti dalaman, yang mengelakkan pengunci overhead mutex.

Prestasi mutlak thread-thread sangat bergantung pada platform. Tetapi saya melakukan beberapa ujian cepat pada PC saya sendiri yang membandingkannya dengan mutabiliti dalaman yang bergantung kepada kunci dan mendapati ia menjadi 10x lebih cepat. Saya tidak mengharapkan hasilnya dibalikkan pada mana -mana platform, tetapi pastikan untuk menjalankan tanda aras anda sendiri jika anda sangat peduli dengan prestasi.

Berikut adalah contoh cara menggunakan refcell untuk mutabiliti dalaman:

<span>use chrono<span>::</span>Utc;
</span>
<span>static START_TIME: String = Utc::now().to_string();
</span>
<span>pub fn main() {
</span>    <span>// ...
</span><span>}
</span>
cubalah untuk diri sendiri di taman permainan!

Sebagai nota sampingan, walaupun benang dalam webassembly berbeza dari benang pada platform x86_64, corak ini dengan thread_local! Refcell juga terpakai apabila menyusun karat untuk berjalan di penyemak imbas. Menggunakan pendekatan yang selamat untuk kod multi-threaded akan berlebihan dalam kes itu. .

Satu kaveat mengenai thread-thread adalah pelaksanaannya bergantung pada platform. Biasanya, ini adalah apa-apa yang anda perhatikan, tetapi sedar bahawa drop-semantik adalah platform yang bergantung kepada itu.

Semua yang dikatakan, penyelesaian untuk global multi-threaded jelas juga berfungsi untuk kes-kes yang dibaca tunggal. Dan tanpa mutabilitas dalaman, mereka seolah-olah sekejap-sekejap-negara.

jadi mari kita lihat yang seterusnya.

pembolehubah global multi-thread dengan inisialisasi runtime

Perpustakaan standard kini tidak mempunyai penyelesaian yang hebat untuk pembolehubah global yang selamat dengan permulaan runtime. Walau bagaimanapun, menggunakan STD :: Sync :: Sekali, ada kemungkinan untuk membina sesuatu yang menggunakan tidak selamat dengan selamat, jika anda tahu apa yang anda lakukan.

Contoh dalam dokumentasi rasmi adalah titik permulaan yang baik. Sekiranya anda juga memerlukan mutabiliti dalaman, anda perlu menggabungkan pendekatan itu dengan kunci baca-tulis atau mutex. Begini cara yang mungkin kelihatan:

<span>use chrono<span>::</span>Utc;
</span>
<span>let START_TIME = Utc::now().to_string();
</span>
<span>pub fn main() {
</span>    <span>let thread_1 = std<span>::thread::</span>spawn(<span>||</span>{
</span>        <span>println!("Started {}, called thread 1 {}", START_TIME.as_ref().unwrap(), Utc::now());
</span>    <span>});
</span>    <span>let thread_2 = std<span>::thread::</span>spawn(<span>||</span>{
</span>        <span>println!("Started {}, called thread 2 {}", START_TIME.as_ref().unwrap(), Utc::now());
</span>    <span>});
</span>
    <span>// Join threads and panic on error to show what went wrong
</span>    thread_1<span>.join().unwrap();
</span>    thread_2<span>.join().unwrap();
</span><span>}
</span>
cubalah untuk diri sendiri di taman permainan!

Jika anda mencari sesuatu yang lebih mudah, saya boleh mengesyorkan salah satu daripada dua peti, yang akan saya bincangkan di bahagian seterusnya.

perpustakaan luaran untuk menguruskan pembolehubah global dalam karat

Berdasarkan populariti dan rasa peribadi, saya ingin mengesyorkan dua perpustakaan yang saya fikir adalah pilihan terbaik untuk pembolehubah global yang mudah dalam karat, sehingga 2021.

Sekali sel sedang dipertimbangkan untuk perpustakaan standard. .

Berikut adalah contoh menggunakan once_cell pada pengkompil yang stabil, dengan ketergantungan tambahan:

<span>use chrono<span>::</span>Utc;
</span>
<span>let START_TIME = Utc::now().to_string();
</span>
<span>pub fn main() {
</span>    <span>let thread_1 = std<span>::thread::</span>spawn(<span>||</span>{
</span>        <span>println!("Started {}, called thread 1 {}", START_TIME.as_ref().unwrap(), Utc::now());
</span>    <span>});
</span>    <span>let thread_2 = std<span>::thread::</span>spawn(<span>||</span>{
</span>        <span>println!("Started {}, called thread 2 {}", START_TIME.as_ref().unwrap(), Utc::now());
</span>    <span>});
</span>
    <span>// Join threads and panic on error to show what went wrong
</span>    thread_1<span>.join().unwrap();
</span>    thread_2<span>.join().unwrap();
</span><span>}
</span>
cubalah untuk diri sendiri di taman permainan!

%0A

%20Akhirnya,%20terdapat%20juga%20statik%20yang%20malas,%20pada%20masa%20ini%20peti%20yang%20paling%20popular%20untuk%20permulaan%20pembolehubah%20global.%20Ia%20menggunakan%20makro%20dengan%20lanjutan%20sintaks%20kecil%20(statik%20ref)%20untuk%20menentukan%20pembolehubah%20global.%20

%20Berikut%20adalah%20contoh%20yang%20sama%20sekali%20lagi,%20diterjemahkan%20dari%20Once_Cell%20ke%20Lazy_static:%20

%0Ause%20chrono::Utc;%0A%0Alet%20START_TIME%20=%20Utc::now().to_string();%0A%0Apub%20fn%20main()%20%7B%0A%20%20%20%20let%20thread_1%20=%20std::thread::spawn(%7C%7C%7B%0A%20%20%20%20%20%20%20%20println!(" started called thread start_time.as_ref utc::now> }); let thread_2 = std::thread::spawn(||{ println!("Started {}, called thread 2 {}", START_TIME.as_ref().unwrap(), Utc::now()); }); // Join threads and panic on error to show what went wrong thread_1.join().unwrap(); thread_2.join().unwrap(); }

cubalah untuk diri sendiri di taman permainan!

Keputusan antara Once_cell dan Lazy_static pada dasarnya beralih ke mana sintaks yang anda sukai.
Juga, kedua -duanya menyokong mutabiliti dalaman. Hanya bungkus rentetan dalam mutex atau rwlock.

Kesimpulan

Ini adalah semua cara (masuk akal) untuk melaksanakan pembolehubah global dalam karat yang saya sedar. Saya harap ia lebih mudah. Tetapi keadaan global sememangnya kompleks. Dalam kombinasi dengan jaminan keselamatan memori Rust, penyelesaian yang mudah ditangkap-Them-semua nampaknya mustahil. Tetapi saya harap penulisan ini telah membantu anda melihat melalui pelbagai pilihan yang ada.

Secara umum, komuniti karat cenderung memberi kuasa maksimum kepada pengguna-yang menjadikan perkara lebih rumit sebagai kesan sampingan.

Sukar untuk menjejaki semua butiran. Akibatnya, saya menghabiskan banyak masa lapang saya bermain -main dengan ciri -ciri karat untuk meneroka kemungkinan. Dalam proses ini, saya biasanya melaksanakan projek hobi yang lebih kecil atau lebih besar - seperti permainan video - dan memuat naiknya ke profil GitHub saya. Kemudian, jika saya dapati sesuatu yang menarik dalam eksperimen saya dengan bahasa, saya menulis tentangnya di blog peribadi saya. Semak bahawa jika anda ingin membaca lebih banyak kandungan karat yang mendalam!

Soalan Lazim mengenai cara menggunakan pembolehubah global secara idiomatically dalam karat

Apakah perbezaan di antara statik dan const dalam karat? Satu konst dalam karat adalah nilai yang tetap, yang bermaksud ia adalah nilai yang tidak akan berubah. Ia sama dengan pembolehubah, tetapi nilainya adalah malar dan tidak boleh diubah. Sebaliknya, pembolehubah statik dalam karat adalah pembolehubah global yang disimpan dalam bahagian data baca sahaja dari binari program. Ia adalah pembolehubah yang boleh didapati di seluruh program, bukan hanya skop di mana ia diisytiharkan. Tidak seperti Const, pembolehubah statik mempunyai alamat tetap dalam ingatan.

Bagaimana saya boleh mengisytiharkan pembolehubah global dalam karat? Inilah contoh:

Global statik: i32 = 10; hanya dan anda tidak dapat mengubahnya.

Bolehkah saya mengubah suai pembolehubah global dalam karat? Ini adalah ciri keselamatan karat untuk mencegah kaum data pada masa penyusunan. Walau bagaimanapun, anda boleh menggunakan Mutex atau RWLOCK dalam modul STD :: SYNC untuk mencapai pembolehubah global yang boleh dimainkan. ! ' Ini bermakna permulaan pembolehubah statik ditangguhkan sehingga ia diakses untuk kali pertama. Ini berguna apabila permulaannya mahal dan anda mahu melakukannya hanya apabila perlu. Contoh bagaimana anda boleh menggunakan 'Lazy_static!'

Lazy_static! { static ref global: mutex = mutex :: new (0); }

Dalam contoh ini, global adalah pemboleh ubah global jenis mutex dan diasaskan dengan Nilai 0. 'Lazy_static!' >

dalam karat, 'statik' digunakan untuk mengisytiharkan pemboleh ubah global yang dibaca sahaja, sementara 'statik mut' digunakan untuk mengisytiharkan pembolehubah global yang boleh berubah. Walau bagaimanapun, 'statik mut' tidak selamat kerana ia boleh menyebabkan tingkah laku yang tidak ditentukan jika dua benang mengakses pembolehubah pada masa yang sama. > Anda boleh mengakses pembolehubah 'statik mut' dengan menggunakan kata kunci 'tidak selamat'. Berikut adalah contoh:

static mut global: i32 = 10;

fn main () { unsafe { global = 20;

println! ("{} ", Global);
}
}

Dalam contoh ini, kata kunci 'tidak selamat' digunakan untuk menunjukkan bahawa kod itu boleh melakukan operasi yang tidak akan ditentukan dalam kod selamat. 🎜> Berapakah seumur hidup pembolehubah global dalam karat? Ini bermakna pembolehubah global dicipta apabila program bermula dan dimusnahkan apabila program berakhir. fungsi. Walau bagaimanapun, anda harus berhati -hati apabila menggunakannya kerana mereka boleh membawa kepada perlumbaan data jika tidak digunakan dengan betul. Secara umumnya disyorkan untuk menggunakan pembolehubah tempatan dan bukannya pembolehubah global apabila mungkin.

Apakah alternatif kepada pembolehubah global dalam karat? Ini termasuk data lulus sebagai hujah fungsi, mengembalikan data dari fungsi, menggunakan struktur data seperti structs dan enums, dan menggunakan primitif konvensional seperti saluran dan kunci.

Atas ialah kandungan terperinci Cara menggunakan pembolehubah global secara idiomatically dalam karat. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn