Lewati ke konten

Argumen Command Line di Rust

Kebanyakan proyek kecil yang cocok untuk latihan, seperti daftar to-do atau penghitung kata, perlu menerima input dari command line, bukan nilai yang ditulis mati (hardcode) di kode sumber. Halaman ini membahas dasar-dasarnya.

use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
println!("{:?}", args);
}

Kalau kamu meng-compile kode ini menjadi program bernama greet lalu menjalankan:

Terminal window
./greet Alice

Kamu akan melihat:

["greet", "Alice"]

Elemen pertama selalu nama program itu sendiri. Argumen yang benar-benar kamu ketik dimulai dari index 1.

use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
println!("Cara pakai: greet <nama>");
return;
}
let name = &args[1];
println!("Halo, {name}!");
}

Jalankan dengan cargo run -- Alice, dan hasilnya:

Halo, Alice!

Kalau dijalankan tanpa argumen, kamu akan melihat pesan cara pakai, bukan program yang crash. Memeriksa args.len() sebelum mengakses index mencegah panic (program berhenti mendadak) kalau seseorang lupa memberikan argumen.

Karena setiap argumen datang sebagai String, kamu sering perlu .parse() (dari halaman Konversi tipe) untuk mengubahnya menjadi angka:

use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
println!("Cara pakai: square <angka>");
return;
}
match args[1].parse::<i32>() {
Ok(n) => println!("{}", n * n),
Err(_) => println!("Itu bukan angka yang valid"),
}
}

Flag adalah argumen yang menyalakan sesuatu, misalnya --shout. Sebelum memakai crate, ada gunanya melihat cara menanganinya sendiri. Triknya supaya mudah dicoba: taruh logikanya di sebuah fungsi yang menerima argumen sebagai slice, yaitu &[String]. Dengan begitu, main bisa mengirim argumen yang asli, dan kamu bisa mengirim daftar buatan sendiri saat bereksperimen:

fn run(args: &[String]) {
let mut shout = false;
let mut names = Vec::new();
// lewati index 0, yaitu nama program
for arg in &args[1..] {
if arg == "--shout" {
shout = true;
} else {
names.push(arg);
}
}
if names.is_empty() {
println!("Cara pakai: greet [--shout] <nama>...");
return;
}
for name in names {
let line = format!("Halo, {name}!");
if shout {
println!("{}", line.to_uppercase());
} else {
println!("{line}");
}
}
}
fn main() {
// Di program sungguhan, kamu akan menulis:
// let args: Vec<String> = std::env::args().collect();
// Di sini kita membuat daftarnya secara manual, supaya bisa jalan juga di Playground.
let args = vec![
String::from("greet"),
String::from("--shout"),
String::from("Ana"),
String::from("Ben"),
];
run(&args);
}

Output:

HALO, ANA!
HALO, BEN!
▶ Coba sendiri

Beberapa hal yang perlu diperhatikan:

  • &args[1..] berisi semua argumen kecuali nama program. Flag bisa muncul di mana saja: greet Ana --shout Ben juga berfungsi.
  • Hapus --shout dari daftar lalu jalankan lagi: kamu akan mendapat sapaan biasa. Hapus juga nama-namanya, dan kamu akan mendapat pesan cara pakai.
  • Karena run tidak peduli dari mana daftarnya berasal, menggantinya dengan std::env::args().collect() cukup dengan mengubah satu baris di main.

Cara ini cukup untuk satu atau dua flag. Begitu kamu juga ingin versi pendek (-s), nilai setelah flag (--count 3), dan pesan --help, perulangan buatan sendiri ini akan cepat membengkak. Saat itulah waktunya beralih ke clap.

Untuk lebih dari beberapa argumen: pakai clap

Section titled “Untuk lebih dari beberapa argumen: pakai clap”

Mengakses args lewat index secara manual cepat jadi merepotkan begitu kamu butuh flag (--verbose), nilai opsional, atau output --help yang membantu. Solusi standarnya adalah crate (library Rust) clap, yang ditambahkan dengan:

Terminal window
cargo add clap --features derive
use clap::Parser;
#[derive(Parser)]
struct Args {
name: String,
#[arg(short, long, default_value_t = 1)]
count: u32,
}
fn main() {
let args = Args::parse();
for _ in 0..args.count {
println!("Halo, {}!", args.name);
}
}

Dengan ini kamu mendapat parsing argumen, validasi, dan pesan --help yang berfungsi, semuanya dibuat otomatis dari definisi struct. Kamu tidak butuh clap untuk skrip singkat, tapi untuk program yang akan kamu pakai lebih dari sekali, crate ini menghemat banyak pekerjaan manual.

Playground tidak bisa mengirim argumen sungguhan, jadi kedua latihan dimulai dari Vec<String> buatan sendiri yang bentuknya sama persis dengan hasil env::args().collect(). Di komputermu sendiri, ganti dengan yang asli dan coba cargo run -- ....

Diberikan vec!["notes", "add", "beli susu"] (sebagai String), cetak berapa banyak argumen yang diketik pengguna (tidak termasuk nama program), lalu cetak setiap argumen beserta posisinya, mulai dari 1.

Petunjuk: jumlahnya adalah args.len() - 1. Perulangan for i in 1..args.len() memberimu setiap index setelah nama program.

Lihat solusi
fn main() {
// anggap saja ini berasal dari std::env::args().collect()
let args = vec![
String::from("notes"),
String::from("add"),
String::from("beli susu"),
];
println!("Kamu memberikan {} argumen", args.len() - 1);
for i in 1..args.len() {
println!("{i}: {}", args[i]);
}
}

Output:

Kamu memberikan 2 argumen
1: add
2: beli susu
▶ Coba sendiri

"beli susu" dihitung sebagai satu argumen: di command line sungguhan kamu mengetiknya dengan tanda kutip (cargo run -- add "beli susu"), dan shell meneruskannya sebagai satu string. Index 0 tetap nama program, karena itulah perulangannya dimulai dari 1.

Diberikan vec!["sum", "4", "10", "x", "6"], jumlahkan setiap argumen yang merupakan angka valid, dan cetak peringatan untuk yang bukan angka. Terakhir, cetak totalnya.

Petunjuk: lakukan perulangan pada &args[1..] dan gunakan match arg.parse::<i32>(), seperti di Mengubah argumen menjadi angka. Simpan let mut total = 0; di luar perulangan.

Lihat solusi
fn main() {
let args = vec![
String::from("sum"),
String::from("4"),
String::from("10"),
String::from("x"),
String::from("6"),
];
let mut total = 0;
for arg in &args[1..] {
match arg.parse::<i32>() {
Ok(n) => total += n,
Err(_) => println!("Melewati '{arg}': bukan angka"),
}
}
println!("Total: {total}");
}

Output:

Melewati 'x': bukan angka
Total: 20
▶ Coba sendiri

Setiap argumen datang sebagai teks, bahkan "4", jadi masing-masing harus di-parse. Melewati input yang salah sambil menampilkan pesan lebih ramah daripada membuat program crash. Kamu juga bisa berhenti di input salah yang pertama dengan return, kalau itu lebih cocok untuk programmu.

  • std::env::args().collect() memberimu Vec<String> berisi argumen command line; index 0 selalu nama program.
  • Periksa args.len() sebelum mengakses index, supaya argumen yang tidak ada tidak membuat programmu panic.
  • .parse() mengubah argumen String menjadi angka, sama seperti di tempat lain.
  • Taruh penanganan argumen di fungsi yang menerima &[String], supaya kamu bisa mencobanya dengan daftar buatan sendiri.
  • Untuk apa pun yang lebih dari beberapa argumen sederhana, crate clap adalah pilihan standar yang sudah teruji.

Kuis singkat

1. Saat kamu memanggil env::args().collect(), apa elemen pertama dari Vec yang dihasilkan?

2. Kenapa perlu memeriksa args.len() sebelum mengakses args lewat index?

3. Apa yang diberikan crate clap yang tidak kamu dapat dari mengakses args secara manual?

Skor: 0 / 3