JRG 8 · Dasar JRG
Struct & Method
Membuat tipe datamu sendiri. Supaya "titik" tidak lagi berupa dua variabel yang kebetulan berdekatan, melainkan satu benda utuh.
tipeMasalahnya dulu
Bayangkan kamu menyimpan data siswa: nama, nilai, dan kehadiran. Tanpa struct, ketiganya jadi variabel terpisah — dan tidak ada yang mengikat mereka.
pub fn main() {
let nama = "Sari"
let nilai = 88
let hadir = 95
wok(nama, nilai, hadir)
}Sari 88 95Sekarang bayangkan ada 30 siswa. Struct menyelesaikan itu:
struct Siswa {
pub nama: string,
pub nilai: int,
pub hadir: int
}
pub fn main() {
let s = Siswa { nama: "Sari", nilai: 88, hadir: 95 }
wok(s)
wok("Nama :", s.nama)
wok("Nilai:", s.nilai)
}Siswa {hadir: 95, nama: Sari, nilai: 88}
Nama : Sari
Nilai: 88pub: field yang boleh dilihat dari luar
Perhatikan kata pub di depan setiap field tadi. Tanpa itu, field hanya bisa dibaca dari dalam method tipe itu sendiri — dan JRG menolak kalau kamu mencoba membacanya dari luar.
struct Dompet {
saldo: int // tanpa pub -> tertutup
}
pub fn main() {
let d = Dompet { saldo: 50000 }
wok(d.saldo)
}error: field `saldo` di `Dompet` bersifat private — cuma bisa diakses dari dalam method tipe itu sendiri atau turunannya. Tambahkan `pub` di depan field itu di deklarasi struct kalau memang harus publik.
--> private.jrg:7:9
|
7 | wok(d.saldo)
| ^^^^^^^
|struct Dompet { saldo: int }
impl Dompet {
fn baru(awal: int) -> Dompet { return Dompet { saldo: awal } }
fn lihat(self) -> int { return self.saldo }
fn tarik(self, n: int) -> Dompet {
if n > self.saldo { return self } // aturannya di sini saja
return Dompet { saldo: self.saldo - n }
}
}
pub fn main() {
var d = Dompet::baru(50000)
d = d.tarik(20000)
d = d.tarik(999999) // ditolak diam-diam oleh aturannya
wok("Saldo:", d.lihat())
}Saldo: 30000Method: fungsi milik sebuah tipe
Blok impl menempelkan fungsi ke sebuah struct. Di dalamnya, self berarti “benda yang sedang dipanggil”.
struct Siswa {
nama: string,
nilai: int,
hadir: int
}
impl Siswa {
fn lulus(self) -> bool {
return self.nilai >= 75 && self.hadir >= 80
}
fn ringkas(self) -> string {
return self.nama + ": " + self.nilai + (self.lulus() $ " (lulus)" : " (ulang)")
}
}
pub fn main() {
let a = Siswa { nama: "Sari", nilai: 88, hadir: 95 }
let b = Siswa { nama: "Budi", nilai: 60, hadir: 90 }
wok(a.ringkas())
wok(b.ringkas())
}Sari: 88 (lulus)
Budi: 60 (ulang)Pembuat (constructor)
Method tanpa self dipanggil lewat nama tipenya. Biasa dipakai untuk membuat isi awal.
struct Titik {
x: float,
y: float
}
impl Titik {
fn baru(x: float, y: float) -> Titik {
return Titik { x: x, y: y }
}
fn asal() -> Titik {
return Titik { x: 0.0, y: 0.0 }
}
fn jarakKe(self, lain: Titik) -> float {
let dx = self.x - lain.x
let dy = self.y - lain.y
return math::sqrt(dx * dx + dy * dy)
}
}
pub fn main() {
let p = Titik::baru(3.0, 4.0)
wok("Jarak ke titik asal:", p.jarakKe(Titik::asal()))
}Jarak ke titik asal: 5.0Nilai bawaan untuk field
struct Pengaturan {
pub judul: string = "Tanpa judul",
pub lebar: int = 80,
pub tinggi: int = 24
}
pub fn main() {
let a = Pengaturan {}
let b = Pengaturan { judul: "Laporan" }
wok(a)
wok(b)
}Pengaturan {judul: Tanpa judul, lebar: 80, tinggi: 24}
Pengaturan {judul: Laporan, lebar: 80, tinggi: 24}Nilai tidak pernah berbagi tempat
Kalau kamu menyalin sebuah struct ke nama lain, keduanya berdiri sendiri. Mengubah satu tidak menyentuh yang lain — ini aturan pokok JRG.
struct Kotak { pub isi: int }
pub fn main() {
var a = Kotak { isi: 1 }
var b = a // salinan, bukan penunjuk yang sama
b.isi = 99
wok("a:", a.isi, " b:", b.isi)
}a: 1 b: 99Menampilkan struct dengan caramu sendiri
Kalau sebuah tipe punya method bernama to_string, semua tempat yang mencetak akan memakainya.
struct Uang { jumlah: int }
impl Uang {
fn to_string(self) -> string {
return "Rp" + self.jumlah
}
}
pub fn main() {
let harga = Uang { jumlah: 12500 }
wok(harga)
wok("Total:", harga)
}Rp12500
Total: Rp12500Kuis 1
Apa arti self di dalam blok impl?
Tepat. Kalau kamu memanggil a.lulus(), maka self adalah a.
Pikirkan a.lulus() — siapa self di sana?
Kuis 2
Sesudah var b = a lalu b.isi = 99, berapa a.isi?
Betul. Di JRG penugasan membuat salinan; dua nama tidak pernah berbagi isi.
Aturan pokok JRG: nilai tidak pernah berbagi tempat.
Kuis 3
Bagaimana memanggil method yang tidak punya self?
Tepat — lewat nama tipenya, memakai ::.
Tanpa self ia tidak terikat ke benda tertentu, jadi dipanggil lewat nama tipenya.
Latihan mandiri
1. Buat struct Persegi dengan field sisi, dan method luas() serta keliling().
2. Tambahkan method lebihBesarDari(lain) yang menjawab true/false.
fn luas(self) -> int { return self.sisi * self.sisi }, keliling 4 * self.sisi.fn lebihBesarDari(self, lain: Persegi) -> bool { return self.luas() > lain.luas() }.