Komentar biasa // dari Chapter sebelumnya hanya terlihat oleh orang yang membuka source code. Begitu crate kita dipakai orang lain — atau bahkan dipakai diri sendiri dari proyek berbeda — catatan internal tersebut tidak pernah sampai ke pembaca: mereka melihat fungsi pub tanpa penjelasan, menebak makna parameter dari namanya, dan tidak punya contoh cara memanggilnya. Rust menjawab kebutuhan ini dengan doc comment ///, komentar yang sengaja ditulis agar diproses menjadi dokumentasi API. Materi testing sudah menunjukkan bahwa blok kode di dalam doc comment ikut dijalankan sebagai doc test; Chapter ini memperluas penggunaannya ke seluruh item publik — fungsi, struct, field, hingga modul — dan menegaskan aturan menempelnya doc comment pada item.

Aturan: /// Menempel pada Item di Bawahnya #

Doc comment dibuka dengan tiga garis miring /// dan berlaku untuk tepat satu item — item pertama yang muncul setelah komentar tersebut berakhir. Item yang layak didokumentasikan dengan /// meliputi fungsi, struct, field struct, enum, variant enum, trait, method di blok impl, hingga modul. Isi doc comment ditulis dalam format Markdown: kita bisa memakai teks tebal dengan **teks**, kode inline dengan backtick, heading dengan #, dan blok kode berpagar.

Bedanya dengan komentar biasa bersifat fundamental: // dibuang lexer dan hilang selamanya, sedangkan /// disimpan sebagai atribut #[doc = "..."] pada item oleh compiler. Karena tersimpan sebagai bagian dari item, teks tersebut dapat dikumpulkan oleh alat rustdoc — mesin pembangkit dokumentasi yang akan kita kenal lebih dekat pada Chapter rustdoc dan cargo doc. Karena /// melekat pada item, penempatannya juga dijaga ketat oleh compiler, sebagaimana akan kita lihat pada bagian penutup Chapter ini.

Mekanisme: rustdoc Mengekstrak, Markdown Menjadi HTML #

Saat cargo test atau cargo doc berjalan, rustdoc memindai seluruh atribut #[doc] hasil parsing, menggabungkan potongan /// yang berurutan menjadi satu dokumen Markdown per item, lalu memrosesnya dalam dua jalur. Jalur pertama merender Markdown menjadi halaman HTML — paragraf pertama doc comment berperan sebagai ringkasan singkat yang muncul di daftar item dan hasil pencarian. Jalur kedua mengekstrak setiap blok kode berpagar di dalam doc comment dan membungkusnya menjadi program kecil yang dikompilasi sebagai pengguna eksternal crate — inilah doc test yang sudah kita jalankan pada section testing. Dengan mekanisme ini, dokumentasi, contoh, dan test bertemu di satu tempat: contoh yang salah otomatis gagal di cargo test.

Contoh: Mendokumentasikan Struct dan Fungsinya #

Buat proyek library baru dengan cargo new gudang --lib, lalu isi src/lib.rs berikut:

rust
/// Menyimpan data satu barang di gudang.
///
/// Struct ini dipakai untuk mencatat **nama barang**, jumlah unit, dan
/// lokasi rak penyimpanan.
pub struct Barang {
    /// Nama barang, contohnya `"Kopi Arabika"`.
    pub nama: String,

    /// Jumlah unit barang yang tersedia di gudang.
    pub jumlah: u32,

    /// Kode lokasi rak, contohnya `"A-07"`.
    pub rak: String,
}

/// Menghitung total nilai stok satu barang.
///
/// Nilai dihitung dengan mengalikan `jumlah` barang dengan `harga_satuan`.
///
/// # Examples
///
/// ```
/// let kopi = gudang::Barang {
///     nama: String::from("Kopi Arabika"),
///     jumlah: 10,
///     rak: String::from("A-07"),
/// };
///
/// let total = gudang::nilai_stok(&kopi, 25_000);
/// assert_eq!(total, 250_000);
/// ```
pub fn nilai_stok(barang: &Barang, harga_satuan: u32) -> u32 {
    barang.jumlah * harga_satuan
}

Jalankan test untuk memastikan contoh di documentation benar-benar dieksekusi:

bash
cargo test

Output yang Dihasilkan:

text
   Compiling gudang v0.1.0 (/tmp/w5b-dokitem)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.14s
     Running unittests src/lib.rs (target/debug/deps/gudang-ca9262378e0c3a18)

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests gudang

running 1 test
test src/lib.rs - nilai_stok (line 22) ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

all doctests ran in 0.14s; merged doctests compilation took 0.14s

Laporan Doc-tests gudang menunjukkan satu test bernama src/lib.rs - nilai_stok (line 22) lulus — contoh di doc comment terbukti hidup. Mari kita bedah kode di atas:

  1. Baris 1-4 (/// Menyimpan data satu barang ...): doc comment empat baris untuk struct Barang. Paragraf pertama (Menyimpan data satu barang di gudang.) menjadi ringkasan singkat yang tampil di daftar item; paragraf kedua masuk ke halaman detail.
  2. Baris 4-5 (pub struct Barang {): struct yang menjadi pemilik doc comment — hanya satu item di bawah komentar yang didokumentasikan.
  3. Baris 6, 9, dan 12 (/// Nama barang..., /// Jumlah unit..., /// Kode lokasi...): doc comment per field publik. Praktik ini penting karena setiap field pub adalah bagian dari API — pembaca struct perlu tahu format nilai yang diharapkan.
  4. Baris 16-18 (/// Menghitung total nilai stok satu barang.): doc comment fungsi nilai_stok dengan penjelasan mekanisme perhitungan. Kata `jumlah` dan `harga_satuan` dalam backtick dirender sebagai kode inline di HTML.
  5. Baris 20 (/// # Examples): heading Markdown di dalam doc comment. rustdoc merendernya sebagai section tersendiri di halaman dokumentasi fungsi; konvensi section standar ini akan kita bahas tuntas pada Chapter Bagian Dokumentasi Standar.
  6. Baris 22-31 (blok kode berpagar di dalam doc comment): blok ``` di dalam /// adalah doc test. Rustdoc membungkusnya menjadi program eksternal yang memanggil gudang::Barang dan gudang::nilai_stok lewat nama crate — karena itu pemanggilan wajib memakai prefiks gudang::.
  7. Baris 32 (pub fn nilai_stok(...)): fungsi yang didokumentasikan. Karena doc test memanggilnya dari luar crate, fungsi ini wajib pub; item privat tidak akan bisa diakses oleh doc test.
  8. Baris laporan test src/lib.rs - nilai_stok (line 22) ... ok: angka line 22 adalah baris pembuka pagar blok contoh di file sumber — cara cepat melompat ke contoh yang gagal ketika dokumentasi berbohong.

Doc Comment yang Tidak Menempel #

Karena /// wajib menempel pada item, compiler menolak doc comment yang menggantung tanpa item di bawahnya. Kode berikut gagal dikompilasi:

rust
fn main() {
    println!("hai");
}

/// Dokumentasi untuk item yang tidak ada.

Pesan error compiler:

text
error: expected item after doc comment
 --> src/main.rs:5:1
  |
5 | /// Dokumentasi untuk item yang tidak ada.
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this doc comment doesn't document anything

error: could not compile `gudang` (bin "gudang") due to 1 previous error

Pesan expected item after doc comment menyatakan masalahnya secara gamblang: ada doc comment, tetapi tidak ada item untuk menerimanya. Kasus umumnya adalah baris kosong atau komentar lain disisipkan memisahkan /// dari itemnya, atau doc comment tertinggal setelah item di bawahnya dihapus. Perbaikannya: pastikan /// berdiri tepat di atas item yang dimaksudkan.

Markdown di Dalam Doc Comment #

Rustdoc memproses Markdown standar, jadi doc comment bisa memuat daftar bertitik, tabel, heading bertingkat, dan bahkan catatan kaki. Dua hal patut diperhatikan. Pertama, heading level satu # di dalam doc comment menjadi judul section di halaman item — # Examples pada contoh kita adalah contohnya. Kedua, potongan Markdown yang terlihat seperti tautan ke item lain, misalnya [Barang], otomatis dihubungkan rustdoc ke halaman item tersebut — fitur intra-doc link yang akan kita praktikkan pada Chapter rustdoc dan cargo doc.

Ringkasan #

Doc comment /// menempel pada tepat satu item di bawahnya, tersimpan sebagai atribut item, lalu dikumpulkan rustdoc menjadi dokumentasi Markdown yang dirender ke HTML dan diuji lewat doc test. Field pub pun layak didokumentasikan sendiri, heading # Examples menjadi section standar, dan doc comment tanpa item memicu error expected item after doc comment. Ada satu posisi yang belum tercakup: bagaimana mendokumentasikan crate secara keseluruhan atau modul sebagai wadah? Untuk itu Rust menyediakan bentuk //!, materi Chapter berikutnya.