Komuniti Rust telah aktif membincangkan corak pengurusan memori dalam implementasi Antara Muka Fungsi Asing (FFI), yang tercetus oleh artikel blog yang mencadangkan bahawa Rust memerlukan pernyataan defer
seperti Go. Ini telah membawa kepada perbincangan mendalam tentang amalan terbaik dan perangkap berpotensi dalam pengurusan memori antara bahasa.
Isu Utama
Perbincangan ini berkisar tentang cabaran dalam menguruskan memori apabila mengantaramuka antara kod Rust dan C, terutamanya apabila berurusan dengan memori yang diperuntukkan yang perlu dibebaskan. Walaupun sesetengah pembangun menyokong mekanisme defer
seperti Go, komuniti secara umumnya menunjuk kepada sifat Drop
Rust yang sedia ada sebagai penyelesaian yang lebih idiomatik dan selamat.
Amalan Terbaik untuk Pengurusan Memori FFI
Konsensus komuniti sangat menekankan beberapa prinsip utama untuk implementasi FFI yang selamat:
- Memori harus sentiasa dibebaskan dalam bahasa/pustaka yang sama yang memperuntukkannya
- Sifat
Drop
Rust harus dimanfaatkan untuk pengurusan sumber automatik - Jenis pembungkus harus digunakan untuk mengenkapsulasi sumber FFI
Box<T>
dan rujukan boleh digunakan dengan selamat dalam sempadan FFI kerana perwakilan memori mereka yang dijamin
Penyelesaian Corak Drop
Bukannya menggunakan defer
atau pengurusan memori manual, pendekatan yang disyorkan adalah untuk mencipta jenis pembungkus yang mengimplementasi sifat Drop
:
struct MyForeignPtr(*mut c_void);
impl Drop for MyForeignPtr {
fn drop(&mut self) {
unsafe { my_free_func(self.0); }
}
}
Corak ini memastikan sumber dibersihkan dengan betul apabila keluar dari skop, sambil mengekalkan jaminan keselamatan Rust.
Pendekatan Alternatif
Untuk kes di mana Vec<T>
perlu dihantar merentasi sempadan FFI, beberapa alternatif telah dicadangkan:
- Menggunakan
Box<[T]>
untuk tatasusunan yang tidak boleh diubah - Menggunakan
Box<Vec<T>>
apabila pengubahsuaian vektor diperlukan - Mengimplementasi semantik pemilikan yang jelas melalui jenis tersuai
- Menggunakan pendekatan berasaskan pemegang seperti deskriptor fail
Perangkap Biasa
Perbincangan mendedahkan beberapa kesilapan biasa dalam implementasi FFI:
- Cubaan untuk membebaskan memori yang diperuntukkan dalam satu bahasa dari bahasa lain
- Salah faham tentang pemilikan penunjuk merentasi sempadan bahasa
- Andaian yang salah tentang keserasian pengperuntuk
- Pengendalian yang tidak betul untuk penunjuk null dalam antara muka C
Kesimpulan
Walaupun artikel asal oleh Philippe Gaultier membangkitkan kebimbangan yang sah tentang kerumitan FFI, maklum balas komuniti menunjukkan bahawa Rust sudah mempunyai mekanisme yang mantap untuk menangani senario ini. Kuncinya bukan untuk menambah ciri bahasa baru seperti defer
, tetapi untuk lebih memahami dan menggunakan corak yang sedia ada, terutamanya sifat Drop
dan pengkapsulan sumber yang betul.
Konsensusnya adalah bahawa menulis kod FFI yang selamat dan boleh diselenggara memerlukan pemahaman menyeluruh tentang model memori kedua-dua bahasa dan komitmen untuk mengikuti amalan terbaik yang telah ditetapkan dan bukannya cuba memaksa corak dari bahasa lain ke dalam ekosistem Rust.