Komentar #
Komentar di Rust bukan sekadar catatan yang diabaikan compiler. Rust membedakan secara tegas antara komentar biasa dan komentar dokumentasi — yang terakhir diproses oleh tool rustdoc untuk menghasilkan dokumentasi HTML siap pakai, lengkap dengan contoh kode yang bisa diuji secara otomatis. Ini berarti dokumentasi di ekosistem Rust bukan pekerjaan terpisah yang dilakukan di wiki atau file README, melainkan bagian integral dari kode itu sendiri. Artikel ini membahas semua jenis komentar di Rust, cara menulis dokumentasi yang efektif, dan — yang sama pentingnya — kapan sebaiknya tidak menulis komentar sama sekali.
Empat Jenis Komentar Rust #
Sebelum masuk ke detail masing-masing, penting memahami peta besarnya. Rust memiliki empat jenis komentar dengan tujuan yang berbeda:
flowchart TD
K[Komentar Rust]
K --> B[Komentar Biasa\nDiabaikan compiler sepenuhnya]
K --> D[Komentar Dokumentasi\nDiproses rustdoc → HTML]
B --> B1["// komentar satu baris"]
B --> B2["/* komentar blok */"]
D --> D1["/// mendokumentasikan item di bawahnya\nfungsi, struct, enum, trait, field"]
D --> D2["//! mendokumentasikan item yang memuatnya\nmodul, crate, file"]| Sintaks | Jenis | Diproses rustdoc | Digunakan untuk |
|---|---|---|---|
// | Komentar baris | Tidak | Catatan internal, penjelasan logika |
/* */ | Komentar blok | Tidak | Menonaktifkan blok kode sementara |
/// | Doc comment luar | Ya | Fungsi, struct, enum, trait, field |
//! | Doc comment dalam | Ya | Modul, crate, file lib.rs / main.rs |
Komentar Baris (//)
#
Komentar baris adalah yang paling umum digunakan sehari-hari. Semua teks setelah // hingga akhir baris diabaikan sepenuhnya oleh compiler.
fn main() {
// Ini komentar baris — compiler tidak melihat baris ini sama sekali
let suhu = 36; // komentar bisa juga diletakkan di akhir baris kode
// Komentar bisa mencakup beberapa baris
// dengan menambahkan // di setiap baris
// Tidak ada cara untuk "melanjutkan" komentar baris ke baris berikutnya
let tekanan = 101;
println!("Suhu: {}°C, Tekanan: {} kPa", suhu, tekanan);
}
Komentar untuk Menonaktifkan Kode Sementara #
Salah satu penggunaan praktis komentar baris adalah menonaktifkan kode saat debugging — menulis alternatif sementara tanpa menghapus kode asli.
fn hitung_diskon(harga: f64, pelanggan_vip: bool) -> f64 {
// Implementasi lama — flat 10%
// harga * 0.9
// Implementasi baru — VIP dapat 20%, pelanggan biasa 5%
if pelanggan_vip {
harga * 0.8
} else {
harga * 0.95
}
}
Kode yang dikomentari dan ditinggal dalam waktu lama menjadi “dead code” yang membingungkan. Jika kode lama tidak relevan, hapus saja — version control (Git) menyimpan riwayatnya. Komentar kode hanya boleh ada sementara selama proses pengembangan aktif.
Komentar Blok (/* */)
#
Komentar blok membungkus teks di antara /* dan */. Tidak seperti komentar baris, komentar blok bisa berada di tengah ekspresi atau menonaktifkan banyak baris sekaligus.
fn main() {
/* Ini komentar blok
yang mencakup beberapa baris
tanpa perlu // di setiap baris */
let x = 5;
// Komentar blok bisa digunakan di tengah ekspresi
// Ini jarang digunakan tapi valid secara sintaks
let hasil = /* nilai awal */ 10 + /* tambahan */ 5;
println!("{}", hasil); // 15
}
Komentar Blok Bersarang #
Tidak seperti banyak bahasa lain (C, Java, Go), Rust mendukung komentar blok yang bersarang — komentar blok di dalam komentar blok. Ini sangat berguna saat kamu ingin menonaktifkan kode yang di dalamnya sudah ada komentar blok.
fn main() {
/*
Menonaktifkan seluruh blok ini untuk sementara:
/*
Ini blok komentar di dalam komentar blok.
Di C/Java ini akan menyebabkan error sintaks.
Di Rust, ini valid karena komentar blok bersarang didukung.
*/
let x = hitung_sesuatu();
proses(x);
*/
println!("Hanya baris ini yang aktif");
}
Komentar Dokumentasi (///)
#
Komentar dokumentasi menggunakan /// dan ditempatkan tepat di atas item yang didokumentasikan. Kontennya mendukung Markdown penuh — heading, bold, italic, code block, list, dan link semuanya bisa digunakan.
/// Menghitung luas persegi panjang.
///
/// Fungsi ini menerima lebar dan tinggi dalam satuan piksel dan
/// mengembalikan luas dalam satuan piksel persegi.
///
/// # Arguments
///
/// * `lebar` - Lebar persegi panjang, harus lebih dari 0
/// * `tinggi` - Tinggi persegi panjang, harus lebih dari 0
///
/// # Returns
///
/// Luas persegi panjang sebagai `u32`.
///
/// # Panics
///
/// Fungsi ini tidak panic. Untuk input tidak valid, gunakan [`luas_aman`].
///
/// # Examples
///
/// ```
/// let hasil = luas(10, 5);
/// assert_eq!(hasil, 50);
/// ```
fn luas(lebar: u32, tinggi: u32) -> u32 {
lebar * tinggi
}
Section Standar dalam Doc Comment #
Ekosistem Rust punya konvensi section yang sudah disepakati komunitas. Mengikutinya memastikan dokumentasi kamu konsisten dengan crate-crate populer seperti std, serde, dan tokio.
| Section | Markdown heading | Isi |
|---|---|---|
| Deskripsi | (tidak ada heading) | Paragraf pertama — ringkasan singkat satu kalimat |
| Detail | (tidak ada heading) | Paragraf tambahan — penjelasan lebih dalam |
# Arguments | # Arguments | Daftar parameter dengan tipe dan constraint |
# Returns | # Returns | Penjelasan return value |
# Errors | # Errors | Kondisi yang menyebabkan Err(...) dikembalikan |
# Panics | # Panics | Kondisi yang menyebabkan fungsi panic |
# Safety | # Safety | Invariant yang harus dipenuhi pemanggil (untuk unsafe fn) |
# Examples | # Examples | Contoh penggunaan — selalu sertakan ini |
use std::num::ParseIntError;
/// Mengonversi string menjadi integer positif.
///
/// String harus merepresentasikan angka desimal tanpa karakter selain digit.
/// Spasi di awal dan akhir **tidak** otomatis di-trim.
///
/// # Arguments
///
/// * `input` - Slice string yang akan dikonversi
///
/// # Returns
///
/// `Ok(u32)` jika konversi berhasil, atau `Err` jika input tidak valid
/// atau merepresentasikan nilai negatif.
///
/// # Errors
///
/// Mengembalikan `Err(ParseIntError)` jika:
/// - String bukan representasi angka yang valid
/// - String mengandung karakter non-digit
/// - Nilai melebihi batas `u32::MAX`
///
/// # Examples
///
/// ```
/// let n = parse_positif("42").unwrap();
/// assert_eq!(n, 42u32);
///
/// assert!(parse_positif("abc").is_err());
/// assert!(parse_positif("-5").is_err());
/// ```
fn parse_positif(input: &str) -> Result<u32, ParseIntError> {
input.trim().parse::<u32>()
}
Doc Test — Komentar yang Bisa Diuji #
Ini adalah fitur yang membuat komentar dokumentasi Rust berbeda secara fundamental dari javadoc atau docstring Python biasa. Setiap blok kode di dalam komentar /// yang diapit triple backtick dijalankan sebagai test saat kamu menjalankan cargo test.
/// Membalik string yang diberikan.
///
/// # Examples
///
/// ```
/// let hasil = balik_string("halo");
/// assert_eq!(hasil, "olah");
///
/// // String kosong tetap kosong setelah dibalik
/// assert_eq!(balik_string(""), "");
///
/// // String dengan satu karakter tidak berubah
/// assert_eq!(balik_string("x"), "x");
/// ```
fn balik_string(s: &str) -> String {
s.chars().rev().collect()
}
Jalankan dengan:
cargo test --doc
Output:
running 1 test
test src/lib.rs - balik_string (line 5) ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
Mengontrol Perilaku Doc Test #
Kamu bisa mengontrol bagaimana doc test dijalankan dengan anotasi di baris pembuka code block:
/// Contoh dengan berbagai anotasi doc test:
///
/// Kode yang tidak ditampilkan di dokumentasi tapi tetap dijalankan:
/// ```
/// # use std::collections::HashMap; // baris dengan # tidak muncul di HTML
/// # let mut map = HashMap::new();
/// map.insert("kunci", "nilai");
/// assert_eq!(map.get("kunci"), Some(&"nilai"));
/// ```
///
/// Kode yang ditampilkan tapi tidak dijalankan (hanya ilustrasi):
/// ```no_run
/// // Ini tidak dijalankan — biasanya untuk kode yang butuh network atau file I/O
/// let koneksi = buka_koneksi("localhost:8080");
/// ```
///
/// Kode yang diharapkan tidak bisa dikompilasi:
/// ```compile_fail
/// let x: i32 = "ini bukan angka"; // seharusnya compile error
/// ```
///
/// Kode yang diabaikan sama sekali:
/// ```ignore
/// // Kode ini tidak dikompilasi maupun dijalankan
/// kode_yang_belum_selesai();
/// ```
fn contoh_anotasi() {}
| Anotasi | Dikompilasi | Dijalankan | Muncul di HTML |
|---|---|---|---|
| (tanpa anotasi) | Ya | Ya | Ya |
no_run | Ya | Tidak | Ya |
compile_fail | Harus gagal | Tidak | Ya |
ignore | Tidak | Tidak | Ya |
Baris diawali # | Ya | Ya | Tidak |
Komentar Dokumentasi Tingkat Modul (//!)
#
Berbeda dari /// yang mendokumentasikan item di bawahnya, //! mendokumentasikan item yang memuatnya — yaitu modul atau crate tempat komentar itu berada. Letakkan di baris pertama file lib.rs, main.rs, atau file modul.
//! # Kalkulator Geometri
//!
//! Crate ini menyediakan fungsi-fungsi untuk menghitung properti
//! berbagai bentuk geometri dua dimensi dan tiga dimensi.
//!
//! ## Penggunaan Cepat
//!
//! ```
//! use geometri::persegi_panjang;
//!
//! let luas = persegi_panjang::luas(10.0, 5.0);
//! assert_eq!(luas, 50.0);
//! ```
//!
//! ## Fitur yang Tersedia
//!
//! - `persegi_panjang` — luas, keliling, diagonal
//! - `lingkaran` — luas, keliling, busur
//! - `segitiga` — luas, keliling, ketinggian
//!
//! ## Catatan Versi
//!
//! Mulai versi 2.0, semua fungsi menggunakan `f64` sebagai tipe default.
// Kode modul di bawah ini...
pub mod persegi_panjang {
/// Menghitung luas persegi panjang.
pub fn luas(lebar: f64, tinggi: f64) -> f64 {
lebar * tinggi
}
}
Komentar Tingkat Modul untuk Modul Bersarang #
// src/jaringan/mod.rs
//! Modul jaringan — penanganan koneksi TCP/UDP dan HTTP client.
//!
//! Semua operasi jaringan bersifat asinkron menggunakan `tokio`.
//! Pastikan runtime tokio aktif sebelum menggunakan fungsi-fungsi di modul ini.
pub mod tcp;
pub mod http;
Mendokumentasikan Struct dan Field #
Komentar dokumentasi bisa diterapkan tidak hanya ke fungsi, tapi juga ke struct, field, enum variant, trait, dan konstanta.
/// Representasi sebuah pengguna dalam sistem.
///
/// Struct ini menyimpan informasi dasar pengguna dan digunakan
/// di seluruh lapisan aplikasi mulai dari database hingga presentasi.
pub struct Pengguna {
/// Nama lengkap pengguna — boleh mengandung spasi dan karakter Unicode.
pub nama: String,
/// Alamat email yang sudah divalidasi format-nya.
///
/// Email belum tentu sudah diverifikasi kepemilikannya —
/// cek field `email_terverifikasi` untuk status verifikasi.
pub email: String,
/// Jumlah poin loyalty yang dimiliki pengguna.
///
/// Nilai ini bertambah setiap kali pengguna melakukan transaksi.
/// Tidak bisa bernilai negatif.
pub poin: u32,
// Field private — tidak perlu doc comment karena tidak terekspos ke publik
aktif: bool,
}
impl Pengguna {
/// Membuat pengguna baru dengan poin awal nol.
///
/// # Arguments
///
/// * `nama` - Nama lengkap pengguna
/// * `email` - Alamat email yang sudah divalidasi
///
/// # Examples
///
/// ```
/// # use crate::Pengguna;
/// let user = Pengguna::baru("Budi Santoso", "[email protected]");
/// assert_eq!(user.poin, 0);
/// ```
pub fn baru(nama: &str, email: &str) -> Self {
Pengguna {
nama: nama.to_string(),
email: email.to_string(),
poin: 0,
aktif: true,
}
}
}
Mendokumentasikan Enum #
/// Status pemrosesan sebuah pesanan.
///
/// Enum ini merepresentasikan seluruh siklus hidup pesanan
/// dari saat dibuat hingga selesai atau dibatalkan.
#[derive(Debug, PartialEq)]
pub enum StatusPesanan {
/// Pesanan baru dibuat, belum ada tindakan.
Baru,
/// Pesanan sedang diverifikasi oleh sistem.
///
/// Pada tahap ini pembayaran belum dikonfirmasi.
Diverifikasi,
/// Pesanan sedang diproses.
///
/// Field `oleh` menyimpan ID karyawan yang memproses.
Diproses { oleh: String },
/// Pesanan sudah dikirim ke alamat tujuan.
///
/// # Fields
///
/// * `nomor_resi` - Nomor pelacakan pengiriman dari kurir
/// * `estimasi_tiba` - Perkiraan tanggal tiba dalam format YYYY-MM-DD
Dikirim {
nomor_resi: String,
estimasi_tiba: String,
},
/// Pesanan selesai dan sudah diterima pelanggan.
Selesai,
/// Pesanan dibatalkan beserta alasannya.
Dibatalkan(String),
}
Menghasilkan Dokumentasi dengan rustdoc #
rustdoc adalah tool bawaan yang mengubah komentar /// dan //! menjadi situs dokumentasi HTML. Kamu tidak perlu menginstalnya terpisah — ia sudah termasuk dalam toolchain Rust.
# Generate dokumentasi untuk crate saat ini
cargo doc
# Generate dan langsung buka di browser
cargo doc --open
# Sertakan dependensi dalam dokumentasi
cargo doc --no-deps # hanya crate kamu sendiri (lebih cepat)
# Generate dengan fitur tertentu aktif
cargo doc --features "fitur-a fitur-b"
Hasil dokumentasi akan ada di target/doc/nama_crate/index.html. Untuk crate library, ini adalah halaman yang akan dilihat pengguna di docs.rs setelah kamu mempublikasikan crate ke crates.io.
sequenceDiagram
participant Dev as Developer
participant Cargo as cargo doc
participant Rustdoc as rustdoc
participant HTML as Dokumentasi HTML
Dev->>Cargo: cargo doc --open
Cargo->>Rustdoc: Parsing source files
Rustdoc->>Rustdoc: Ekstrak komentar /// dan //!
Rustdoc->>Rustdoc: Render Markdown → HTML
Rustdoc->>Rustdoc: Jalankan doc tests
Rustdoc->>HTML: target/doc/nama_crate/
HTML->>Dev: Buka di browserKapan Tidak Perlu Menulis Komentar #
Komentar yang buruk lebih berbahaya dari tidak ada komentar — ia menciptakan ilusi bahwa kode sudah terdokumentasi padahal penjelasannya salah atau menyesatkan. Rust mendorong kode yang self-documenting: nama yang deskriptif, tipe yang ekspresif, dan struktur yang jelas.
// ANTI-PATTERN: komentar yang hanya mengulang apa yang kode sudah bilang
// Inisialisasi counter dengan nilai nol
let mut counter = 0;
// Tambah satu ke counter
counter += 1;
// BENAR: tidak perlu komentar — kode sudah cukup jelas
let mut counter = 0;
counter += 1;
// ANTI-PATTERN: nama variabel yang ambigu memaksa komentar menjelaskannya
// d = jumlah hari dalam sebulan ini
let d = 30;
// BENAR: nama yang deskriptif membuat komentar tidak perlu
let hari_dalam_bulan = 30;
// ANTI-PATTERN: komentar yang menjelaskan "apa" — yang sudah jelas dari kode
// Loop melalui setiap elemen array
for elemen in &data {
proses(elemen);
}
// BENAR: komentar yang menjelaskan "mengapa" — informasi yang tidak terlihat dari kode
// Proses dilakukan secara berurutan (bukan paralel) karena setiap elemen
// bergantung pada hasil pemrosesan elemen sebelumnya
for elemen in &data {
proses(elemen);
}
// ANTI-PATTERN: komentar yang sudah tidak akurat karena kode berubah tapi komentar tidak
// Fungsi ini selalu mengembalikan nilai positif
fn hitung(x: i32) -> i32 {
x * x - 10 // Sekarang bisa negatif, tapi komentar tidak diupdate
}
// BENAR: hapus komentar yang tidak akurat, atau update dengan informasi yang benar
/// Menghitung kuadrat x dikurangi 10. Bisa mengembalikan nilai negatif
/// jika nilai absolut `x` kurang dari ~3.16.
fn hitung(x: i32) -> i32 {
x * x - 10
}
Panduan Singkat: Tulis Komentar untuk “Mengapa”, Bukan “Apa” #
flowchart TD
Q{Apakah kode ini\nperlu komentar?}
Q --> A{Apakah kode sudah\njelas dibaca sendiri?}
A -- Ya --> B{Apakah ada alasan\nnon-obvious di baliknya?}
B -- Tidak --> C[Tidak perlu komentar\nKode sudah self-documenting]
B -- Ya --> D["Tulis komentar 'mengapa'\nbukan 'apa'"]
A -- Tidak --> E{Bisakah diperbaiki\ndengan nama yang lebih baik?}
E -- Ya --> F[Rename variabel/fungsi\nHapus komentar]
E -- Tidak --> G[Tulis komentar penjelasan\nPertimbangkan ekstrak ke fungsi]Ringkasan #
- Empat jenis komentar di Rust:
//(baris),/* */(blok),///(doc comment item),//!(doc comment modul/crate).///bukan sekadar catatan — diprosesrustdocmenjadi dokumentasi HTML dan dijalankan sebagai test olehcargo test --doc.- Doc test menjaga dokumentasi tetap akurat — contoh kode di komentar
///dikompilasi dan dijalankan, sehingga tidak bisa out of sync dengan implementasi.- Section standar
# Arguments,# Returns,# Errors,# Panics,# Examplesmembuat dokumentasi konsisten dengan ekosistem Rust.//!untuk crate dan modul — letakkan di baris pertamalib.rsataumod.rsuntuk mendokumentasikan keseluruhan unit tersebut.- Komentar blok Rust mendukung nesting —
/* /* */ */valid, berbeda dari C atau Java.- Tulis komentar untuk “mengapa”, bukan “apa” — kode yang baik menjelaskan sendiri apa yang ia lakukan; komentar bertugas menjelaskan alasan di balik keputusan yang tidak terlihat dari kode.
- Komentar yang salah lebih buruk dari tidak ada komentar — selalu perbarui komentar saat mengubah kode, atau hapus jika sudah tidak relevan.