Setiap nilai di dunia nyata memiliki bentuk yang berbeda: jumlah penumpang berupa bilangan bulat, berat badan mengandung angka desimal, status pesanan hanya punya dua kemungkinan, dan nama pelanggan berupa rangkaian huruf. PHP menangani perbedaan ini secara longgar karena interpreter mengingat tipe setiap nilai secara dinamis. Rust memilih jalur sebaliknya: kompilator harus tahu tipe dan ukuran memori setiap nilai sebelum program dijalankan, sehingga mesin tidak perlu membawa informasi tipe pada saat runtime. Pada Chapter ini kita akan mengenal empat tipe skalair milik Rust, yaitu integer, floating point, boolean, dan char, beserta rentang nilainya.
Empat Kategori Tipe Skalair #
Tipe skalair adalah tipe yang menyimpan tepat satu nilai, lawan dari tipe komposit seperti tuple dan array yang mengelompokkan banyak nilai. Rust membagi tipe skalair menjadi empat kategori, dan setiap kategori menempati ukuran memori yang tetap:
- Integer: bilangan bulat, misalnya
i32danu8. - Floating point: bilangan desimal, yaitu
f32danf64. - Boolean: nilai kebenaran
trueataufalse, ditulisbool. - char: satu karakter Unicode, selalu berukuran 4 byte.
Keempat kategori tersebut akan kita bahas satu per satu dengan contoh kode nyata.
Tipe Integer #
Tipe integer dibedakan oleh dua hal: apakah nilainya boleh negatif (signed, diawali i) atau tidak (unsigned, diawali u), serta berapa byte memorinya. Tabel berikut merangkum pilihan yang tersedia:
| Tipe | Rentang nilai | Ukuran |
|---|---|---|
i8 | -128 s.d. 127 | 1 byte |
u8 | 0 s.d. 255 | 1 byte |
i16 | -32.768 s.d. 32.767 | 2 byte |
u16 | 0 s.d. 65.535 | 2 byte |
i32 | -2.147.483.648 s.d. 2.147.483.647 | 4 byte |
u32 | 0 s.d. 4.294.967.295 | 4 byte |
i64 | -9.223.372.036.854.775.808 s.d. 9.223.372.036.854.775.807 | 8 byte |
u64 | 0 s.d. 18.446.744.073.709.551.615 | 8 byte |
i128 / u128 | rentang sangat besar | 16 byte |
isize / usize | mengikuti arsitektur komputer | 4 atau 8 byte |
Saat kita menulis bilangan bulat tanpa anotasi tipe, kompilator memilih i32 sebagai bawaan karena tipe tersebut dianggap cukup besar untuk kebutuhan umum sekaligus tetap cepat diproses. Kode berikut memakai beberapa tipe integer secara eksplisit:
fn main() {
let suhu_selisih: i8 = -40;
let jumlah_roti: u8 = 200;
let populasi_kota: u32 = 8_500_000;
let populasi_negara: i64 = 275_000_000;
println!("Selisih suhu: {} derajat", suhu_selisih);
println!("Jumlah roti: {} buah", jumlah_roti);
println!("Populasi kota: {} jiwa", populasi_kota);
println!("Populasi negara: {} jiwa", populasi_negara);
}Output yang Dihasilkan:
Selisih suhu: -40 derajat
Jumlah roti: 200 buah
Populasi kota: 8500000 jiwa
Populasi negara: 275000000 jiwaMari kita bedah pemilihan tipe pada tiap barisnya:
- Baris 2 (
let suhu_selisih: i8 = -40;): nilai bisa negatif, sehingga tipe signedi8tepat; angka-40berada jauh di dalam rentang -128 s.d. 127. - Baris 3 (
let jumlah_roti: u8 = 200;): jumlah roti tidak mungkin negatif, sehinggau8yang menyimpan 0 s.d. 255 sudah memadai. - Baris 4 (
let populasi_kota: u32 = 8_500_000;): tanda garis bawah pada8_500_000murni pemisah ribuan agar mudah dibaca; nilainya tetap8500000. - Baris 5 (
let populasi_negara: i64 = 275_000_000;): angka besar untuk populasi negara disimpan padai64agar tersedia ruang tumbuh yang lebar.
Anotasi tipe menuntut kita jujur terhadap rentang. Kompilator langsung menolak nilai yang tidak muat:
fn main() {
let jumlah_roti: u8 = 300;
println!("Jumlah roti: {}", jumlah_roti);
}Pesan galatnya berbunyi:
error: literal out of range for `u8`
--> main.rs:2:27
|
2 | let jumlah_roti: u8 = 300;
| ^^^
|
= note: the literal `300` does not fit into the type `u8` whose range is `0..=255`
= note: `#[deny(overflowing_literals)]` on by default
error: aborting due to 1 previous errorGalat tersebut menegaskan bahwa 300 tidak muat dalam u8 yang hanya menampung 0..=255. Kita harus memilih tipe yang lebih besar seperti u16, atau memperbaiki nilai datanya.
Bentuk Penulisan Literal Integer #
Rust menerima bilangan bulat dalam empat sistem bilangan sekaligus: desimal, heksadesimal, oktal, dan biner. Bentuk 0x, 0o, dan 0b masing-masing menjadi penanda sistem bilangannya, sedangkan awalan b'...' (hanya untuk satu karakter ASCII) menghasilkan nilai byte bertipe u8:
fn main() {
let desimal = 1_000_000;
let heksadesimal = 0xFF;
let oktal = 0o77;
let biner = 0b1010_1010;
let byte_a = b'A';
println!("Desimal: {}", desimal);
println!("Heksadesimal: {}", heksadesimal);
println!("Oktal: {}", oktal);
println!("Biner: {}", biner);
println!("Byte: {}", byte_a);
}Output yang Dihasilkan:
Desimal: 1000000
Heksadesimal: 255
Oktal: 63
Biner: 170
Byte: 65Nilai 0xFF adalah 255 dalam heksadesimal, 0o77 adalah 63 dalam oktal, 0b1010_1010 adalah 170 dalam biner, dan b'A' adalah 65 karena huruf A memiliki kode ASCII 65. Keempat literal tersebut menyimpan bilangan bulat biasa; sistem bilangan hanya memengaruhi cara kita menulisnya, bukan tipe hasilnya.
Tipe Floating Point #
Bilangan desimal ditangani dua tipe: f64 dengan presisi ganda (8 byte) dan f32 dengan presisi tunggal (4 byte). Literal desimal tanpa anotasi menjadi f64 karena presisinya lebih aman untuk perhitungan umum. Nilai f32 cukup ketika kita butuh hemat memori, misalnya menyimpan banyak data pengukuran:
fn main() {
let berat: f32 = 72.5;
let tinggi: f64 = 1.78;
println!("Berat: {} kg", berat);
println!("Tinggi: {} m", tinggi);
}Output yang Dihasilkan:
Berat: 72.5 kg
Tinggi: 1.78 mVariable berat memakai f32 karena formulir data kesehatan hanya membutuhkan satu angka di belakang koma, sedangkan tinggi mengikuti bawaan f64. Kedua tipe ini mengikuti standar IEEE 754, sehingga perilakunya sama dengan bilangan desimal di bahasa lain.
Tipe Boolean #
Tipe bool hanya menyimpan dua nilai: true atau false. Tipe ini berukuran 1 byte dan menjadi bahan bakar utama percabangan if yang akan kita pelajari pada section Kontrol Alur:
fn main() {
let sudah_lunas = true;
let sudah_dikirim = false;
println!("Pesanan sudah lunas: {}", sudah_lunas);
println!("Pesanan sudah dikirim: {}", sudah_dikirim);
}Output yang Dihasilkan:
Pesanan sudah lunas: true
Pesanan sudah dikirim: falseBerbeda dengan PHP, Rust tidak menganggap angka 0 sebagai false atau angka selain nol sebagai true. Nilai boolean hanya bisa dilahirkan dari literal true/false, hasil operator perbandingan, atau operator logika.
Tipe char #
Tipe char menyimpan satu karakter dan selalu berukuran 4 byte karena memakai representasi Unicode Scalar Value. Rentang Unicode yang luas membuat char Rust jauh lebih kaya daripada satu byte ASCII: huruf, angka, simbol mata uang, bahkan emoji semuanya sah:
fn main() {
let huruf_awal: char = 'B';
let simbol_mata_uang: char = '₨';
let emoji_kepiting: char = '🦀';
println!("Huruf: {}", huruf_awal);
println!("Simbol: {}", simbol_mata_uang);
println!("Emoji: {}", emoji_kepiting);
}Output yang Dihasilkan:
Huruf: B
Simbol: ₨
Emoji: 🦀Perhatikan bahwa literal char ditulis dengan tanda kutip tunggal ('B'), berbeda dengan teks yang lebih panjang yang memakai tanda kutip ganda dan bertipe string. Pembahasan string secara mendalam menunggu section String dan Teks agar kita sudah menguasai ownership terlebih dahulu.
Ringkasan #
Tipe skalair Rust menyimpan satu nilai dengan ukuran memori yang pasti: integer dibagi menjadi signed dan unsigned dengan rentang yang bergantung jumlah byte, floating point tersedia dalam f32 dan f64, boolean menyimpan true atau false, dan char menyimpan satu karakter Unicode berukuran 4 byte. Literal integer dapat ditulis dalam empat sistem bilangan dengan pemisah ribuan berupa garis bawah. Nilai di luar rentang tipe, seperti 300 pada u8, ditolak langsung oleh kompilator. Selanjutnya kita akan mengelompokkan beberapa nilai sekaligus menggunakan tuple dan array.