Gambaran Umum Pembuatan Kode
Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan GO di Coddy. Pelajaran 84 dari 107.
Code generation adalah alternatif untuk reflection yang membuat kode sumber Go saat compile, bukan memeriksa tipe saat runtime. Pendekatan ini memberikan keamanan tipe dan performa yang lebih baik, sekaligus mengurangi kode boilerplate yang berulang.
Go menyediakan perintah go generate untuk mengotomatiskan pembuatan kode. Kamu menempatkan direktif komentar khusus di file sumbermu, lalu menjalankan go generate untuk mengeksekusi alat yang ditentukan:
//go:generate stringer -type=Status
type Status int
const (
Pending Status = iota
Active
Completed
)Menjalankan go generate ./... memanggil tool stringer, yang membuat file baru berisi method String() untuk tipe Status. Kode yang dihasilkan adalah kode Go biasa yang dikompilasi bersama programmu.
Alat pembuat kode yang umum dalam ekosistem Go mencakup stringer untuk method string enum, mockgen untuk membuat mock pengujian dari interface, dan protoc untuk membuat kode dari definisi Protocol Buffer. Banyak ORM dan framework API juga menggunakan pembuatan kode untuk membuat query database yang aman terhadap tipe atau kode client.
Keunggulan utamanya dibandingkan reflection adalah kode yang dihasilkan diperiksa oleh compiler. Error terdeteksi saat proses build, bukan saat runtime. Kekurangannya adalah adanya langkah build tambahan dan file hasil generasi yang perlu kamu kelola di repositorimu. Untuk pola OOP yang memerlukan implementasi berulang pada banyak tipe, code generation sering memberikan keseimbangan terbaik antara keamanan dan kemudahan.
Tantangan
MudahMari buat generator kode yang membuat method String() untuk tipe mirip enum! Walaupun kita tidak bisa menjalankan go generate sungguhan di lingkungan ini, kamu akan menyimulasikan cara kerja alat pembuat kode: menghasilkan kode sumber Go secara terprogram berdasarkan definisi tipe.
Kamu akan mengatur kodemu dalam dua file:
generator.go: Buat logika pembuatan kodemu.Buat struct
EnumTypeyang mewakili definisi tipe mirip enum denganName(string) danValues(slice berisi string yang mewakili nama konstanta).Buat fungsi
GenerateStringMethod(e EnumType) stringyang menghasilkan kode sumber Go untuk methodString(). Kode yang dihasilkan harus mengikuti pola ini:func (e TypeName) String() string { switch e { case Value1: return "Value1" case Value2: return "Value2" default: return "Unknown" } }Buat juga fungsi
GenerateConstants(e EnumType) stringyang menghasilkan deklarasi konstanta menggunakaniota:const ( Value1 TypeName = iota Value2 Value3 )Terakhir, buat
GenerateFullCode(e EnumType) stringyang menggabungkan kedua output dengan komentar header yang menunjukkan bahwa ini adalah kode yang dihasilkan:// Code generated by enum generator. DO NOT EDIT. [constants] [string method]main.go: Gunakan generator-mu untuk menghasilkan kode bagi berbagai tipe enum.Baca nama tipe enum, lalu baca jumlah nilai yang diikuti setiap nama nilai. Berikan informasi ini kepada generator-mu, lalu cetak kode lengkap yang dihasilkan.
Input berikut akan diberikan:
- Baris 1: Nama tipe enum
- Baris 2: Jumlah nilai
- Baris-baris berikutnya: Setiap nama nilai
Contohnya, jika diberikan:
Status
3
Pending
Active
CompletedOutput-mu seharusnya:
// Code generated by enum generator. DO NOT EDIT.
const (
Pending Status = iota
Active
Completed
)
func (e Status) String() string {
switch e {
case Pending:
return "Pending"
case Active:
return "Active"
case Completed:
return "Completed"
default:
return "Unknown"
}
}Dan jika diberikan:
Priority
2
Low
HighOutput-mu seharusnya:
// Code generated by enum generator. DO NOT EDIT.
const (
Low Priority = iota
High
)
func (e Priority) String() string {
switch e {
case Low:
return "Low"
case High:
return "High"
default:
return "Unknown"
}
}Latihan ini menunjukkan konsep inti di balik alat seperti stringer: menghasilkan kode yang berulang tetapi aman terhadap tipe saat compile, alih-alih menggunakan reflection saat runtime. Generator-mu menghasilkan kode Go yang valid, yang dapat disimpan ke file dan di-compile bersama bagian lain dari proyek.
Coba sendiri
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Baca nama tipe enum
typeName, _ := reader.ReadString('\n')
typeName = strings.TrimSpace(typeName)
// Baca jumlah nilai
countStr, _ := reader.ReadString('\n')
count, _ := strconv.Atoi(strings.TrimSpace(countStr))
// Baca nama setiap nilai
values := make([]string, count)
for i := 0; i < count; i++ {
value, _ := reader.ReadString('\n')
values[i] = strings.TrimSpace(value)
}
// TODO: Buat EnumType dengan data yang telah dibaca
// TODO: Hasilkan dan cetak kode lengkap menggunakan GenerateFullCode
}
Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.
Semua pelajaran di Pemrograman Berorientasi Objek
1Dasar-Dasar OOP di Go
File EksternalWorkspace Go dan modulePaket dan ImporNama yang Diekspor dan Tidak DieksporPengantar OOP di Gostruct sebagai classMendefinisikan method pada structPointer receiver vs value receiverInisialisasi structFungsi KonstruktorUlasan: Kalkulator Sederhana4Interface
Pengenalan InterfaceImplementasi ImplisitInterface sebagai KontrakInterface Kosong (any)Type AssertionType SwitchKomposisi InterfaceInterface Stringer & ErrorUlasan: Kalkulator Bentuk7Enkapsulasi
Field yang Diekspor vs Tidak DieksporEnkapsulasi Tingkat PackageMethod Getter dan SetterPenyembunyian Informasi di GoRingkasan: Data Siswa10Generics (Go 1.18+)
Pengantar GenericsParameter TipeBatasan TipeStruct GenerikCara Alternatif untuk Method GenerikRingkasan Koleksi Generik2Mendalami Tipe dan Struct
Tipe Dasar dan KompositDefinisi Tipe KustomTag StructStruct AnonimStruct BersarangNilai Nol dan Nilai BawaanRangkuman: Buku Kontak5Komposisi daripada Pewarisan
Mengapa Go Tidak Memiliki PewarisanDasar Penyematan StructPromosi methodMenyematkan Beberapa StructPenyematan vs AgregasiMembayangi method yang DisematkanRangkuman: Hierarki Karyawan8Penanganan Error & OOP
Interface errorTipe Error KustomPembungkusan Error (fmt.Errorf)Error Sentinelerrors.Is() dan errors.As()Panic, Defer, dan RecoverRangkuman: Parser File3Pointer dan Memori
Dasar-Dasar Pointer di GoPointer ke StructPass by Value vs ReferenceFungsi new()Garbage Collection di GoRekap: Pembuat Linked List6Polimorfisme di Go
Polimorfisme melalui InterfaceDuck Typing di GoAturan Pemenuhan InterfaceKoleksi PolimorfikInjeksi DependensiRangkuman: Pemroses Pembayaran9Konkruensi & OOP
Dasar-dasar GoroutineChannel & KomunikasiChannel Ber-buffer vs Tanpa BufferPernyataan selectsync.Mutex & sync.RWMutexsync.WaitGroupDesain Struct yang Aman untuk ThreadRingkasan: Worker Pool12Konsep OOP Lanjutan
Pola Opsi FungsionalPola Builder di GoMethod ChainingAlias Tipe vs DefinisiDasar-Dasar ReflectionGambaran Umum Pembuatan KodeLatihan sendiri: Compiler Go online