Sejak program pertama kita, kata main selalu hadir tanpa pernah dibedah. Kita tahu program “mulai dari situ”, tetapi belum pernah bertanya bagaimana sistem operasi menemukannya, bagaimana program memberi tahu bahwa eksekusi berhasil atau gagal, dan bagaimana program menerima data dari pengguna saat dijalankan. Pada Chapter ini kita akan memperlakukan main sebagai fungsi yang utuh: titik masuk (entry point) yang dipanggil oleh runtime Rust, penghasil exit code yang dibaca sistem operasi, dan pemilik argument baris perintah yang diketik pengguna.
main sebagai Titik Masuk Program #
Runtime Rust membutuhkan satu titik yang pasti untuk memulai eksekusi, dan titik tersebut adalah fungsi main. Saat kita menjalankan berkas hasil kompilasi, runtime menyiapkan lingkungan eksekusi (tumpukan memori, penanganan galat dasar), lalu memanggil fungsi main milik program kita. Ketika main selesai, runtime membersihkan sisanya dan mengembalikan kontrol ke sistem operasi.
Dua konsekuensi penting mengikuti desain ini. Pertama, setiap program Rust yang bisa dieksekusi wajib punya tepat satu fungsi main; tanpa main, kompilasi gagal dengan galat error[E0601]: `main` function not found. Kedua, fungsi selain main tidak pernah berjalan otomatis — sekuat apa pun fungsinya didefinisikan, fungsi hanya hidup kalau dipanggil, dan seluruh rantai pemanggilan pasti berujung pada main.
Membaca Argumen Baris Perintah #
Program CLI (command line interface) menerima masukan langsung dari perintah yang diketik pengguna, misalnya ./sapa Budi mengirim kata Budi ke program sapa. Rust menyediakan akses ke daftar tersebut melalui std::env::args(). Mari kita buat program pemeriksa argument:
use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
println!("Jumlah argumen: {}", args.len());
println!("Nama program: {}", args[0]);
if args.len() > 1 {
println!("Argumen pertama: {}", args[1]);
}
}Kompilasi dan jalankan dengan satu argument tambahan:
rustc --edition 2021 daftar-argumen.rs -o daftar-argumen
./daftar-argumen BudiOutput yang Dihasilkan:
Jumlah argumen: 2
Nama program: ./daftar-argumen
Argumen pertama: BudiMari kita telaah apa yang terjadi pada baris-baris kode di atas:
- Baris 1 (
use std::env;): Statementusemembawa modulenvdari pustaka standar ke ruang nama berkas, sehingga kita cukup menulisenv::args()tanpa jalur lengkapstd::env::args(). - Baris 4 (
let args: Vec<String> = env::args().collect();):env::args()menghasilkan argument satu per satu;.collect()mengumpulkannya menjadiVec<String>, yaitu kumpulan (semacam daftar) yang setiap elemennya bertipeString. AnotasiVec<String>memberi tahu kompiler bentuk kumpulan yang kita inginkan. - Baris 6 (
println!("Jumlah argumen: {}", args.len());):args.len()menghitung elemen koleksi. Hasilnya2karena nama program ikut dihitung sebagai argument pertama. - Baris 7 (
println!("Nama program: {}", args[0]);): Elemen ke-0adalah teks yang dipakai untuk menjalankan program, dalam kasus ini./daftar-argumen. Indeks selalu dimulai dari nol. - Baris 9–11 (
if args.len() > 1 { ... }): Pemeriksaan ini menjaga agar program tidak membacaargs[1]saat pengguna tidak mengirim argument apa pun, karena posisi tersebut belum tentu ada. Argument pengguna yang pertama selalu berada diargs[1].
Semua argument dari baris perintah datang sebagai String — termasuk angka. Kalau program butuh angka untuk dihitung, teks tersebut harus dikonversi terlebih dahulu, topik yang akan kita dalami saat membahas penanganan error.
Exit Code dan Sinyal Berhasil atau Gagal #
Setiap program yang berakhir meninggalkan satu angka untuk sistem operasi, bernama exit code. Konvensinya: 0 berarti sukses, angka selain 0 berarti gagal. Angka ini bukan hiasan — skrip bash, CI/CD, dan alat otomasi lain membacanya lewat variabel khusus $? untuk memutuskan langkah berikutnya, misalnya menghentikan deployment saat program gagal.
Saat main selesai secara wajar tanpa masalah, Rust otomatis melaporkan exit code 0. Untuk mengatur angkanya sendiri, kita memakai std::process::exit:
use std::process;
fn main() {
let args: Vec<String> = std::env::args().collect();
if args.len() < 2 {
println!("Cara pakai: {} <nama>", args[0]);
process::exit(1);
}
println!("Halo, {}! Selamat datang kembali.", args[1]);
process::exit(0);
}Uji kedua skenarionya beserta exit code-nya:
rustc --edition 2021 sapa.rs -o sapa
./sapa
echo $?
./sapa Budi
echo $?Output yang Dihasilkan:
Cara pakai: ./sapa <nama>
1
Halo, Budi! Selamat datang kembali.
0Mari kita telaah alur kedua eksekusi di atas:
- Baris 6 (
if args.len() < 2): Program memeriksa jumlah argument lebih dulu. Pola “periksa dulu, gagal cepat” seperti ini adalah bentuk klasik pemanggilanprocess::exit— kesalahan penggunaan dideteksi sebelum pekerjaan utama dimulai. - Baris 8 (
process::exit(1);): Saat argument kurang, program mencetak petunjuk pemakaian lalu menghentikan seluruh proses seketika dengan exit code1. Baris-baris setelah pemanggilan ini tidak pernah dieksekusi pada skenario pertama. - Baris 11–12 (
println!(...)danprocess::exit(0);): Saat argument lengkap, program menyapa pengguna lalu berakhir dengan exit code0. - Perintah
echo $?: Bash mencetak exit code dari program yang baru saja selesai. Skenario tanpa argument menghasilkan1, skenario denganBudimenghasilkan0.
Pemanggilan process::exit di akhir dengan kode 0 pada contoh di atas sengaja ditampilkan untuk kejelasan; pada praktiknya, baris tersebut bisa dihapus karena Rust sudah melaporkan 0 saat main selesai dengan wajar. Yang tidak boleh dihapus adalah pemanggilan dengan kode galat di jalur kegagalan.
Ringkasan #
Fungsi main adalah titik masuk yang dipanggil runtime Rust; tanpa main, program gagal dikompilasi. Argument baris perintah diakses melalui std::env::args() sebagai koleksi String dengan nama program di posisi pertama. Exit code 0 menandakan sukses dan dilaporkan otomatis saat main selesai, sedangkan std::process::exit(kode) menghentikan program seketika dengan kode yang kita pilih untuk jalur kegagalan. Program kita kini bisa menerima masukan dan melaporkan status ke lingkungannya — dua kemampuan yang membuat Rust cocok untuk perangkat CLI. Selanjutnya kita membedah ruang hidup variabel di dalam fungsi.