Fungsi

Parameter, nilai kembalian, dan body berbasis ekspresi.

Daftar isi

Topik ini membahas cara mendefinisikan fungsi di Rust, mulai dari parameter yang wajib bertipe, nilai kembalian, sampai sifat badan fungsi yang dibangun dari pernyataan dan ekspresi. Setelah membacanya, pembaca dapat memecah program menjadi fungsi-fungsi kecil yang mudah diuji serta memahami mengapa satu tanda titik koma dapat mengubah nilai yang dikembalikan.

Mendefinisikan dan memanggil fungsi#

Fungsi didefinisikan dengan kata kunci fn yang diikuti nama fungsi, daftar parameter dalam tanda kurung, dan badan fungsi dalam kurung kurawal. Pemanggilan dilakukan dengan menuliskan nama fungsi beserta argumennya.

rust sapa.rs
fn sapa(nama: &str) {
    println!("Halo, {nama}!");
}

fn main() {
    sapa("Citra");
    sapa("Budi");
}
text Keluaran
Halo, Citra!
Halo, Budi!

Nama fungsi ditulis dengan huruf kecil dan kata dipisah garis bawah, misalnya sapa atau hitung_rata_rata, dan gaya ini merupakan konvensi yang ditegakkan compiler lewat peringatan gaya penamaan. Urutan definisi tidak dibatasi, sehingga fungsi sapa boleh berada di atas maupun di bawah main dalam satu berkas. Parameter nama bertipe &str, yaitu tipe teks yang hanya dibaca, dan pembahasan tipe teks secara rinci berada pada modul collections. Fungsi sapa tidak mengembalikan nilai apa pun, sehingga tanda panah nilai kembalian tidak dituliskan.

Program yang tumbuh besar dipecah menjadi fungsi-fungsi kecil dengan tugas tunggal, dan nama fungsi yang deskriptif membuat badan main tetap pendek seperti daftar langkah. Setiap fungsi juga menjadi satuan yang mudah diperiksa secara terpisah karena masukannya berupa parameter dan keluarannya berupa nilai kembalian. Konvensi penamaan yang sama berlaku pada variabel maupun berkas sehingga kode dapat dilacak dari namanya.

Parameter dan nilai kembalian#

Setiap parameter fungsi wajib diberi anotasi tipe secara eksplisit, berbeda dengan variabel lokal yang tipenya dapat disimpulkan. Ketentuan ini menjaga kontrak fungsi tetap terbaca dari baris tanda tangan (signature) tanpa perlu membaca isi badannya. Tipe nilai kembalian ditulis setelah tanda panah ->.

rust luas.rs
fn luas_persegi_panjang(panjang: i32, lebar: i32) -> i32 {
    panjang * lebar
}

fn main() {
    let luas = luas_persegi_panjang(30, 40);
    println!("luas: {luas} sentimeter persegi");
}
text Keluaran
luas: 1200 sentimeter persegi

Fungsi luas_persegi_panjang mengembalikan nilai ekspresi terakhir pada badannya tanpa tanda titik koma dan tanpa kata kunci return. Bentuk ini adalah gaya lazim untuk nilai kembalian di akhir fungsi. Kata kunci return tetap tersedia untuk pengembalian lebih awal di tengah badan, misalnya ketika sebuah kondisi terpenuhi dan sisa kode tidak perlu dijalankan. Tipe yang dijanjikan setelah tanda panah harus cocok dengan nilai yang benar-benar dikembalikan, dan ketidakcocokan tersebut ditolak compiler.

Ketika satu fungsi perlu menghasilkan beberapa nilai sekaligus, tuple menjadi pembungkus yang ringkas. Nilai kembalian berupa tuple dapat dipecah langsung di sisi pemanggil, sehingga tidak perlu variabel sementara.

rust statistik.rs
fn statistik(nilai: [i32; 3]) -> (i32, i32) {
    let total = nilai[0] + nilai[1] + nilai[2];
    (total, total / 3)
}

fn main() {
    let (total, rata) = statistik([80, 90, 100]);
    println!("total: {total}");
    println!("rata-rata: {rata}");
}
text Keluaran
total: 270
rata-rata: 90

Fungsi statistik menerima array tiga bilangan bulat dan mengembalikan tuple berisi total serta rata-ratanya. Pemanggil memecah hasilnya dengan pola let (total, rata), dan pembagian bilangan bulat memangkas pecahan. Pola ini sering dipakai pada fungsi yang menghitung beberapa ukuran dari satu sumber data.

Pernyataan dan ekspresi#

Rust membedakan pernyataan (statement) dan ekspresi (expression) secara tegas. Pernyataan menjalankan instruksi tanpa menghasilkan nilai, dan contohnya adalah deklarasi let. Sebaliknya, ekspresi menghasilkan nilai yang dapat dipakai lebih lanjut, dan contohnya adalah operasi aritmetika, pemanggilan fungsi, pemanggilan macro, maupun blok kurung kurawal itu sendiri.

rust ekspresi.rs
fn main() {
    let y = {
        let x = 3;
        x + 1
    };

    println!("nilai y: {y}");
}
text Keluaran
nilai y: 4

Blok kurung kurawal pada baris let y = { ... } adalah ekspresi yang nilainya ditentukan oleh ekspresi terakhirnya, yaitu x + 1, sehingga y bernilai 4. Variabel x hanya hidup di dalam blok tersebut dan tidak dapat diakses setelahnya. Sifat yang sama membuat if dapat menghasilkan nilai, dan pemakaian tersebut dibahas pada topik alur kontrol. Perbedaan keduanya dirangkum pada tabel berikut.

AspekPernyataanEkspresi
Hasiltidak menghasilkan nilaimenghasilkan nilai
Contohlet y = 6;6 + 1
Dapat menjadi nilai lettidakya
Akibat titik komamenutup pernyataanmengubahnya menjadi pernyataan

Karena let adalah pernyataan, penulisan let x = (let y = 6); tidak sah karena bagian dalam kurung bukan ekspresi. Blok kurung kurawal tetap sah di posisi tersebut karena blok adalah ekspresi, seperti pada contoh di atas. Aturan ini menjaga sisi kanan tanda sama dengan selalu menghasilkan satu nilai yang tipenya dapat diperiksa.

Kesalahan umum#

Mengakhiri nilai kembalian dengan titik koma. Kesalahan satu karakter ini umum terjadi pada fungsi bernilai kembalian dan menghasilkan error berikut.

bash
printf 'fn lima() -> i32 {\n    5;\n}\n\nfn main() {\n    println!("{}", lima());\n}\n' > salah.rs
rustc --edition=2021 salah.rs 2>&1 | sed -n '1,11p'
text Keluaran
error[E0308]: mismatched types
 --> salah.rs:1:14
  |
1 | fn lima() -> i32 {
  |    ----      ^^^ expected `i32`, found `()`
  |    |
  |    implicitly returns `()` as its body has no tail or `return` expression
2 |     5;
  |      - help: remove this semicolon to return this value

error: aborting due to 1 previous error

Error E0308 menjelaskan bahwa fungsi berjanji mengembalikan i32 tetapi badannya mengembalikan tipe unit (), dan saran perbaikannya adalah menghapus titik koma setelah angka 5. Pesan seperti ini menjadi mudah dibaca seiring bertambahnya pengalaman menulis fungsi bernilai kembalian.

Menghilangkan anotasi tipe parameter. Penulisan fn tambah(a, b) langsung ditolak saat kompilasi karena Rust mengharuskan setiap parameter memiliki tipe yang tertulis. Kebiasaan dari bahasa lain yang menyimpulkan tipe parameter membuat error ini muncul berulang kali pada awalnya. Perlu dicatat bahwa tipe kembalian tetap boleh tidak ditulis ketika fungsi memang tidak menghasilkan nilai, karena ketiadaan tanda panah sudah menyatakan tipe unit.

Ringkasan#

  • Fungsi didefinisikan dengan fn, dinamai dengan huruf kecil bergaris bawah, dan dapat didefinisikan pada urutan mana pun di dalam berkas.
  • Setiap parameter wajib bertipe eksplisit, sedangkan tipe nilai kembalian ditulis setelah tanda panah ->.
  • Nilai kembalian lazim ditulis sebagai ekspresi terakhir tanpa titik koma, dan kata kunci return dipakai untuk pengembalian lebih awal.
  • Blok kurung kurawal adalah ekspresi yang nilainya ditentukan ekspresi terakhirnya, sehingga dapat langsung diikat ke variabel.
  • Titik koma pada ekspresi terakhir mengubah nilai kembalian menjadi tipe unit () dan memicu error E0308.

Referensi#