Saya ingin memiliki modul dengan beberapa struct di dalamnya, masing-masing dalam filenya sendiri. Menggunakan Math
modul sebagai contoh:
Math/
Vector.rs
Matrix.rs
Complex.rs
Saya ingin setiap struct berada dalam modul yang sama, yang akan saya gunakan dari file utama saya, seperti:
use Math::Vector;
fn main() {
// ...
}
Namun sistem modul Rust (yang awalnya agak membingungkan) tidak menyediakan cara yang jelas untuk melakukan ini. Tampaknya hanya memungkinkan Anda untuk memiliki seluruh modul Anda dalam satu file. Apakah ini tidak kasar? Jika tidak, bagaimana cara melakukannya?
foo::bar::Baz
harus didefinisikan difoo/bar.rs
ataufoo/bar/mod.rs
.Jawaban:
Sistem modul Rust sebenarnya sangat fleksibel dan akan membiarkan Anda mengekspos jenis struktur apa pun yang Anda inginkan sambil menyembunyikan bagaimana kode Anda disusun dalam file.
Saya pikir kuncinya di sini adalah memanfaatkan
pub use
, yang akan memungkinkan Anda mengekspor ulang pengenal dari modul lain. Ada preseden untuk ini distd::io
peti Rust di mana beberapa jenis dari sub-modul diekspor kembali untuk digunakan distd::io
.Untuk mengadaptasi contoh Anda, kita bisa mulai dengan struktur direktori ini:
Ini milik Anda
main.rs
:Dan Anda
src/lib.rs
:Dan akhirnya,
src/vector.rs
:Dan di sinilah keajaiban terjadi. Kami telah mendefinisikan sub-modul
math::vector::vector_a
yang memiliki beberapa implementasi dari jenis vektor khusus. Tapi kami tidak ingin klien perpustakaan Anda peduli bahwa adavector_a
sub-modul. Sebagai gantinya, kami ingin membuatnya tersedia dimath::vector
modul. Ini dilakukan denganpub use self::vector_a::VectorA
, yang mengekspor ulangvector_a::VectorA
pengenal di modul saat ini.Tetapi Anda bertanya bagaimana melakukan ini sehingga Anda dapat meletakkan implementasi vektor khusus Anda di file yang berbeda. Inilah yang
mod vector_b;
garis itu lakukan. Ini menginstruksikan kompiler Rust untuk mencarivector_b.rs
file untuk implementasi modul itu. Dan tentu saja, inilahsrc/vector_b.rs
file kami :Dari perspektif klien, fakta bahwa
VectorA
danVectorB
didefinisikan dalam dua modul berbeda dalam dua file berbeda benar-benar tidak jelas.Jika Anda berada di direktori yang sama dengan
main.rs
, Anda harus dapat menjalankannya dengan:Secara umum, chapter "Crates and Modules" di buku Rust cukup bagus. Ada banyak contoh.
Akhirnya, kompilator Rust juga mencari di sub-direktori untuk Anda secara otomatis. Misalnya, kode di atas tidak akan berfungsi dengan struktur direktori ini:
Perintah untuk mengkompilasi dan menjalankan juga tetap sama.
sumber
math::Vec2
bukanmath::vector::Vec2
. (yaitu, konsep yang sama tetapi satu modul lebih dalam.)Aturan modul Rust adalah:
File matrix.rs 1 dalam direktori math hanyalah modul
math::matrix
. Mudah. Apa yang Anda lihat di sistem file Anda juga ditemukan di kode sumber Anda. Ini adalah korespondensi satu-ke-satu dari jalur file dan jalur modul 2 .Jadi Anda dapat mengimpor struct
Matrix
denganuse math::matrix::Matrix
, karena struct tersebut berada di dalam file matrix.rs dalam direktori math. Tidak senang? Anda lebih sukause math::Matrix;
sebaliknya, bukan? Itu mungkin. Ekspor ulang pengenalmath::matrix::Matrix
di math / mod.rs dengan:Ada langkah lain untuk membuatnya berfungsi. Rust membutuhkan deklarasi modul untuk memuat modul. Tambahkan
mod math;
di main.rs. Jika Anda tidak melakukan itu, Anda mendapatkan pesan kesalahan dari kompilator saat mengimpor seperti ini:Petunjuknya menyesatkan di sini. Tidak perlu peti tambahan, kecuali tentu saja Anda benar-benar bermaksud untuk menulis perpustakaan terpisah.
Tambahkan ini di bagian atas main.rs:
Deklarasi modul juga diperlukan untuk submodul
vector
,matrix
dancomplex
, karenamath
perlu memuatnya untuk mengekspornya kembali. Ekspor ulang pengenal hanya berfungsi jika Anda telah memuat modul pengenal. Artinya, untuk mengekspor ulang pengenalmath::matrix::Matrix
yang perlu Anda tulismod matrix;
. Anda bisa melakukannya di math / mod.rs. Oleh karena itu buatlah file dengan konten ini:Aaa dan kamu selesai.
1 Nama file sumber biasanya dimulai dengan huruf kecil di Rust. Itulah mengapa saya menggunakan matrix.rs dan bukan Matrix.rs.
2 Java berbeda. Anda juga mendeklarasikan jalan dengan
package
. Itu berlebihan. Path sudah terbukti dari lokasi file sumber di sistem file. Mengapa mengulangi informasi ini dalam pernyataan di bagian atas file? Tentu saja terkadang lebih mudah untuk melihat sekilas kode sumber daripada mencari tahu lokasi sistem file dari file tersebut. Saya dapat memahami orang-orang yang mengatakan itu tidak terlalu membingungkan.sumber
Rusts purists mungkin akan menyebut saya sesat dan membenci solusi ini, tapi ini jauh lebih sederhana: cukup lakukan setiap hal dalam file sendiri, lalu gunakan makro " include! " Di mod.rs:
Dengan begitu, Anda tidak mendapatkan modul bersarang tambahan, dan menghindari aturan ekspor dan penulisan ulang yang rumit. Sederhana, efektif, tidak repot.
sumber
use super::*
). Anda tidak dapat menyembunyikan kode dari file lain (yang penting untuk abstraksi aman yang tidak aman digunakan)Baiklah, lawan kompiler saya untuk sementara waktu dan akhirnya berhasil (terima kasih kepada BurntSushi untuk menunjukkannya
pub use
.main.rs:
math / mod.rs:
matematika / vektor.rs
Struct lain dapat ditambahkan dengan cara yang sama. CATATAN: dikompilasi dengan 0.9, bukan master.
sumber
mod math;
dimain.rs
pasangan Andamain
Program dengan perpustakaan Anda. Jika Anda inginmath
modul Anda independen, Anda harus mengkompilasinya secara terpisah dan menautkannya denganextern crate math
(seperti yang ditunjukkan dalam jawaban saya). Di Rust 0.9, mungkin saja sintaksnyaextern mod math
.Saya ingin menambahkan di sini bagaimana Anda menyertakan file Rust ketika mereka sangat bersarang. Saya memiliki struktur berikut:
Bagaimana Anda mengakses
sink.rs
atautoilet.rs
darimain.rs
?Seperti yang disebutkan orang lain, Rust tidak memiliki pengetahuan tentang file. Sebaliknya, ia melihat semuanya sebagai modul dan submodul. Untuk mengakses file di dalam direktori kamar mandi, Anda perlu mengekspornya atau memindahkannya ke atas. Anda melakukan ini dengan menentukan nama file dengan direktori yang ingin Anda akses dan
pub mod filename_inside_the_dir_without_rs_ext
di dalam file.Contoh.
Buat file bernama
bathroom.rs
di dalamhome
direktori:Ekspor nama file:
Buat file bernama di
home.rs
sebelahmain.rs
pub mod
file bathroom.rsDalam
main.rs
use
pernyataan juga bisa digunakan:Termasuk modul saudara lainnya (file) dalam submodul
Jika Anda ingin menggunakan
sink.rs
fromtoilet.rs
, Anda dapat memanggil modul dengan menentukanself
atausuper
kata kunci.Struktur Direktori Akhir
Anda akan berakhir dengan sesuatu seperti ini:
Struktur di atas hanya berfungsi dengan Rust 2018 dan seterusnya. Struktur direktori berikut juga berlaku untuk tahun 2018, tetapi begitulah tahun 2015 dulu berfungsi.
Di mana
home/mod.rs
sama dengan./home.rs
danhome/bathroom/mod.rs
sama denganhome/bathroom.rs
. Rust membuat perubahan ini karena kompilator akan bingung jika Anda menyertakan file dengan nama yang sama dengan direktorinya. Versi 2018 (yang ditampilkan pertama) memperbaiki struktur itu.Lihat repo ini untuk informasi lebih lanjut dan video YouTube ini untuk penjelasan keseluruhan.
Satu hal lagi ... hindari tanda hubung! Gunakan
snake_case
sebagai gantinya.Catatan penting
Anda harus memasukkan semua file ke atas, bahkan jika file dalam tidak diperlukan oleh file tingkat atas.
Ini berarti, bahwa untuk
sink.rs
menemukannyatoilet.rs
, Anda harus memasukkannya dengan menggunakan metode di atas hinggamain.rs
!Dengan kata lain, melakukan
pub mod sink;
atauuse self::sink;
di dalam tidaktoilet.rs
akan berfungsi kecuali Anda telah mengeksposnya sepenuhnyamain.rs
!Oleh karena itu, selalu ingat untuk menyimpan file Anda ke atas!
sumber