Rust: Cara Impor dan Ekspor Modul File pada Project

Bagi developer yang datang dari dunia pemrograman web server atau yang mungkin terbiasa dengan NodeJs atau PHP, mengimport file di dalam project bukanlah sesuatu yang sulit, dan biasanya cenderung mudah karena secara struktur memang cenderung sepele.

Namun bagi kalian yang baru atau mulai mempelajari bahasa Rust, kalian pasti akan menemukan dimana proses import export modul, variabel ataupun komponen lainnya dalam project agak sedikit tricky .

Disini akan saya bahas bagaimana kita dapat memahami cara import-export modul pada project Rust, untuk contoh project source code-nya dapat kalian cek disini untuk lebih lengkapnya.

GitHub - slaveofcode/rust-import-files: Simple example to explains how Rust Import Files/Module
Simple example to explains how Rust Import Files/Module - GitHub - slaveofcode/rust-import-files: Simple example to explains how Rust Import Files/Module

Struktur Project

Semua pembahasan dalam artikel ini akan merujuk pada struktur file di bawah ini.

Struktur Project Acuan

Private By Default

Semua objek dalam project Rust, by default adalah private. Untuk itu dalam mengekspor objek-objek tersebut, kita harus menggunakan keyword pub diikuti dengan nama objek yang diinginkan.

Sebagai contoh, dengan menggunakan struktur file pada gambar sebelumnya, jika kita ingin menggunakan fungsi pada file db.rs, maka yang harus dilakukan adalah.

pub fn get_connection() -> String {
    "get_connection()".to_string()
}
src/db.rs

Lalu pada file main.rs kita dapat menggunakan fungsi tersebut dengan terlebih dahulu mengimport modul yang dimaksud dengan keyword mod <nama_file>.

mod db;
src/main.rs

dan menggunakannya pada program

fn main() {
    let conn = db::get_connection();
    println!("{}", conn);
}
Contoh penggunaan pada main.rs
Nama module dan nama file yang ingin di import haruslah sama, karena Rust akan mencocokan nama modul yang ditulis dengan struktur file project.

Rust Mencocokan Modul dengan File

Ya betul, jika kalian cek contoh kode sebelumnya, Rust tidak mengenal file dalam project kalian, melainkan modul (mod). Rust akan melihat modul-modul yang terdefinisi dan mengambil file dengan nama yang sama dengan modul tersebut.

Jika pada bahasan diatas kita hanya mengimport file, lalu bagaimana jika kita ingin melakukan import sebuah folder atau modul yang terdiri dari submodul lainnya?

Folder Submodul dengan mod.rs

Untuk dapat mengekspos modul dalam folder, kita harus membuat file mod.rs di dalam folder tersebut, lalu nama folder juga harus sama dengan nama modul yang digunakan.

// main.rs

mod page; // akan mencari page.rs atau page/mod.rs
Contoh deklarasi modul page

Sebagai contoh, jika kita mempunyai folder bernama page dalam struktur project diatas (lihat gambar Struktur Project Acuan), maka file mod.rs harus dibuat didalamnya untuk mendeskripsikan modul page tersebut jika ingin digunakan dalam program.

Lalu dalam file mod.rs tadi bisa ditulis modul yang ingin di ekspose dari dalam folder page tersebut, dalam hal ini home dan post

pub mod home;
pub mod post;
src/post/mod.rs
Perhatian: post merupakan folder yang didalamnya juga terdapat file mod.rs untuk melakukan expose modul-modul di dalamnya

Perbedaan Rust edisi 2018 ke bawah

Dalam edisi Rust 2018 ke bawah, kita harus selalu membuat file mod.rs pada setiap folder atau subfolder. Hal ini karena compiler memetakan file-file pada folder tersebut menggunakan file mod.rs tadi.

Oh ya, bagi yang belum paham maksud dari edisi 2018 disini, coba kalian cek file  Cargo.toml di project Rust kalian, pada bagian edition menjelaskan edisi Rust berapa yang akan dijalankan. Pada contoh kali ini saya menggunakan edisi 2021.

[package]
name = "project_structure"
version = "0.1.0"
edition = "2021"
Cargo.toml

Alternatif Baru Untuk Submodul dalam Folder

Melanjutkan dari versi 2018 keatas pada topik sebelumnya, saat ini kita dapat mengekspos modul dalam folder tanpa menggunakan mod.rs, yaitu dengan membuat file dengan nama yang sama dengan folder tersebut.

Merujuk pada asset pada struktur project diatas. File asset akan bertindak sebagai mod.rs (pada kasus sebelumnya) untuk mengekspos modul-modul yang ada dalam folder asset

mod image;
mod video;

pub fn image_png() -> String {
    format!("Static Image {}", image::png_files())
}

pub fn video_mp4() -> String {
    format!("Static Video {}", video::mp4_files())
}
src/asset.rs
pub fn png_files() -> String {
    "PNG Files".to_string()
}
src/asset/image.rs
pub fn mp4_files() -> String {
    "MP4 files".to_string()
}
src/asset/video.rs
mod asset;

fn main() {
    println!("{}", asset::image_png());
    println!("{}", asset::video_mp4());
}
src/main.rs

Import dari "root" project

Sejauh ini kita sudah membahas bagaimana cara melakukan proses import modul di dalam submodul atau file, namun bagaimana jika kita ingin melakukan import modul dari dalam submodul?

Untuk menangani itu, kita dapat menggunakan alias crate untuk import dari "root" project.

Masih mengambil struktur project yang sama dengan sebelumnya, kita dapat melakukan import fungsi image_png() pada modul asset dengan melakukan seperti di bawah ini.

use crate::asset::{image_png}; // diambil dari src/asset.rs

pub fn content_with_image() -> String {
    format!("Content with Image: {}", image_png()).to_string()
}
src/page/post/post_two.rs

Bonus: Menghindari Penggunaan File dengan "hyphen"

Dalam penulisan nama file pada rust, seharusnya tidak mengunakan "hyphen" atau tanda minus - pada struktur project. Karena sudah pasti file tersebut tidak akan bisa diigunakan sebagai modul.

Namun jika hal itu tidak dapat dihindari, kalian tetap dapat menggunakan file tersebut sebagai modul dengan bantuan attribute khusus. Sebagai contoh kalian dapat melihat kode dibawah ini.

#[path = "./static-utils.rs"]
mod static_utils;
import modul pada file berbeda