Metode adalah fungsi def yang didefinisikan di dalam struct dan beroperasi pada field melalui argumen khusus bernama self. Topik ini membahas penulisan metode baca, arti self bawaan sebagai peminjaman, metode mutator dengan mut self, serta metode statik. Setelah topik ini dibaca, metode untuk membaca dan mengubah isi struct dapat ditulis dengan konvensi argumen yang benar.
Metode def di dalam struct#
Metode instance (instance method) adalah metode yang menerima self sebagai argumen pertama dan beroperasi pada satu nilai struct. Nama self merupakan konvensi penamaan yang dipakai dokumentasi resmi Mojo, dan nilai self dikirim otomatis oleh compiler pada setiap pemanggilan melalui notasi titik, misalnya t.jumlah(). Berbeda dengan argumen lain pada def, argumen self tidak wajib memiliki anotasi tipe karena tipenya sudah diketahui dari struct tempat metode itu didefinisikan, meskipun menuliskannya secara eksplisit juga sah. Bentuk eksplisitnya adalah self: Self, dengan Self sebagai penanda tipe struct tempat metode didefinisikan. Tipe kembalian dan anotasi tipe argumen lain ditulis dengan aturan fungsi def biasa.
# tidak-dijalankan
def jumlah(self) -> Int:
return self.x + self.yMetode di dalam struct dapat saling memanggil melalui self, misalnya self.geser(1, 1) dipanggil dari metode lain. Field diakses dengan penulisan self.x, sehingga variabel field tidak pernah tampak tanpa awalan eksplisit. Aturan ini menjaga kejelasan asal setiap nama yang dipakai di dalam metode.
self sebagai peminjaman baca#
Secara bawaan, self diterima sebagai peminjaman yang tidak dapat diubah (immutable borrow), yaitu akses baca ke nilai pemanggil tanpa penyalinan. Metode dengan self bawaan dapat membaca field dan mengembalikan nilai hasil perhitungan, tetapi tidak dapat mengubah isi field. Pendekatan ini mengikuti konvensi argumen bawaan Mojo yang meminjam secara immutable, sehingga pemanggilan metode baca tidak menyalin nilai struct apa pun, berapa pun ukuran struct tersebut. Metode semacam ini tetap dapat mengembalikan nilai baru, misalnya hasil perhitungan atas field yang dibaca, tanpa menyentuh keadaan struct.
Apabila metode memerlukan nilai kerja yang dapat diubah, buat variabel lokal dengan var di dalam metode, lalu operasikan variabel lokal tersebut. Pola ini menjaga self tetap tidak terubah sepanjang metode berjalan. Batasan ini bukan keterbatasan yang mengganggu, melainkan pembatas yang membuat compiler bebas mengevaluasi banyak pemanggilan metode baca tanpa harus mengatur eksklusivitas akses antarpeminjam.
Mengubah nilai dengan mut self#
Metode yang mengubah isi struct wajib mendeklarasikan argumen pertama sebagai mut self. Kata kunci mut menjadikan self peminjaman yang dapat diubah (mutable borrow), sehingga penugasan pada field di dalam metode sah dan perubahannya bertahan setelah metode kembali. Metode semacam ini disebut metode mutator karena mengubah keadaan nilai pemanggilnya.
Peminjaman yang dapat diubah bersifat eksklusif. Selama metode mutator berjalan, nilai yang sama tidak boleh dipinjam oleh pihak lain, dan compiler menegakkan aturan ini pada waktu kompilasi. Dengan demikian, tidak ada dua jalur eksekusi yang mengubah satu nilai secara bersamaan, dan tidak ada pembaca yang melihat nilai setengah berubah. Hasil perubahan dapat dibaca langsung setelah metode kembali, karena mutator bekerja pada nilai pemanggil itu sendiri dan bukan pada salinannya.
Program utuh titik-metode.mojo#
Buat berkas titik-metode.mojo dengan isi berikut, kemudian jalankan.
struct Titik:
var x: Int
var y: Int
def __init__(out self, x: Int, y: Int):
self.x = x
self.y = y
def jumlah(self) -> Int:
return self.x + self.y
def geser(mut self, dx: Int, dy: Int):
self.x += dx
self.y += dy
def main():
var t = Titik(3, 4)
print("jumlah awal:", t.jumlah())
t.geser(2, 5)
print("jumlah setelah geser:", t.jumlah())# jalankan program metode struct
mojo run titik-metode.mojojumlah awal: 7
jumlah setelah geser: 14Metode jumlah memakai self bawaan karena hanya membaca field, sedangkan metode geser memakai mut self karena menambah nilai kedua field. Pemanggilan t.geser(2, 5) mengubah nilai pada t secara permanen, sehingga t.jumlah() yang dipanggil setelahnya mengembalikan 14 dan bukan 7 lagi.
Urutan pemanggilan pada program ini memperlihatkan peran setiap konvensi argumen. Pemanggilan t.jumlah() hanya meminjam t untuk dibaca, sehingga keadaan t tidak berubah. Pemanggilan t.geser(2, 5) meminjam t secara mutabel, menambah kedua field, dan perubahannya tersimpan pada t itu sendiri. Nilai self pada kedua pemanggilan disediakan compiler dari notasi titiknya, sehingga daftar argumen yang ditulis hanyalah 2 dan 5. Dengan pola ini, metode baru cukup ditambahkan di dalam body struct, dan pemanggilannya langsung tersedia pada setiap nilai bertipe tersebut.
Metode statik#
Metode statik (static method) adalah metode milik tipe yang dapat dipanggil tanpa membuat nilai struct terlebih dahulu. Metode ini ditandai decorator @staticmethod dan tidak menerima self, sehingga tidak dapat mengakses field milik instance. Kegunaan utamanya mencakup perilaku yang tidak bergantung pada keadaan satu nilai, penyediaan konstanta, atau pembuatan nilai khusus dari argumen tertentu.
Pemanggilan metode statik dilakukan langsung pada nama struct, misalnya Statistik.rata_rata(30.0, 3). Mojo juga mengizinkan pemanggilan lewat sebuah nilai instance, tetapi bentuk pemanggilan pada tipe lebih umum dipakai karena menyatakan niatnya dengan jelas.
Metode statik cocok untuk perhitungan yang hanya bergantung pada argumennya, misalnya konversi satuan atau penghitungan rata-rata dari total dan banyaknya data. Konversi tipe tetap ditulis secara eksplisit di dalam metode tersebut, sebagaimana Float64(n) memastikan pembagian dilakukan pada tipe operand yang sama. Dengan pemisahan ini, metode instance mengurus keadaan satu nilai, sedangkan metode statik menyediakan operasi umum pada tipe.
struct Statistik:
@staticmethod
def rata_rata(total: Float64, n: Int) -> Float64:
return total / Float64(n)
def main():
print(Statistik.rata_rata(30.0, 3))# jalankan program metode statik
mojo run statik.mojo10.0Perhatikan konversi Float64(n) di dalam metode statik tersebut. Tanpa konversi, pembagian antara Float64 dan Int tidak diterima compiler karena tipe kedua operand harus cocok.
Kesalahan umum#
Menulis metode mutator tanpa mut self adalah kesalahan yang paling sering terjadi. Compiler menolak penugasan pada field karena self bawaan bersifat baca saja. Berkas berikut memperlihatkan penolakan tersebut.
struct Titik:
var x: Int
var y: Int
def __init__(out self, x: Int, y: Int):
self.x = x
self.y = y
def geser(self, dx: Int):
self.x += dx
def main():
var t = Titik(3, 4)
print(t.x)# jalankan berkas yang sengaja keliru
mojo run salah-mutator.mojo/home/kal/my-project/content/mojo/struct-dan-trait/metode-dan-self/salah-mutator.mojo:10:13: error: expression must be mutable for in-place operator destination
self.x += dx
~~~~^~
/home/kal/.pixi/envs/mojo/bin/mojo: error: failed to parse the provided Mojo source modulePesan error menyatakan bahwa sasaran operator penugasan harus dapat diubah. Perbaikannya adalah mengubah tanda tangan metode menjadi def geser(mut self, dx: Int), sehingga penugasan pada self.x sah.
Kesalahan kedua adalah mendefinisikan metode instance tanpa argumen self. Compiler menolaknya dengan pesan self argument must be present in instance method, dan perbaikannya adalah menambahkan self sebagai argumen pertama.
Kesalahan ketiga adalah memanggil metode mutator pada nilai yang sedang dipinjam untuk dibaca, misalnya pada parameter fungsi yang dideklarasikan t: Titik. Compiler menolaknya dengan pesan invalid use of mutating method, karena peminjaman baca tidak boleh menjadi sasaran perubahan. Perbaikannya adalah menyatakan parameter tersebut sebagai mut t: Titik, sehingga eksklusivitas peminjaman mutabel terjaga. Ketiga pesan tersebut muncul selama kompilasi, sehingga program yang memuatnya tidak pernah sampai ke tahap eksekusi.
Ringkasan#
- Metode instance menerima
selfsebagai argumen pertama tanpa anotasi tipe, dan tipenya ditetapkan oleh struct tempat metode didefinisikan. selfbawaan adalah peminjaman baca yang tidak menyalin nilai, cocok untuk metode yang hanya membaca field.- Metode mutator wajib menggunakan
mut self, perubahannya bertahan setelah metode kembali, dan peminjamannya bersifat eksklusif. @staticmethodmenandai metode tanpaselfyang dipanggil pada tipe dan tidak dapat mengakses field milik instance.
Referensi#
- Structs — Mojo Manual
— Bagian resmi tentang metode instance, metode mutator dengan
mut self, dan metode statik pada struct. - Mojo Manual — Indeks dokumentasi resmi bahasa Mojo versi 1.2.0.