Kod Üretimine Genel Bakış
Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 84 / 107.
Code generation, türleri çalışma zamanında incelemek yerine derleme zamanında Go kaynak kodu oluşturan, reflection'a bir alternatiftir. Bu yaklaşım, tekrarlayan kalıp kodu azaltırken tür güvenliği ve daha iyi performans sağlar.
Go, kod üretimini otomatikleştirmek için go generate komutunu sağlar. Kaynak dosyanıza özel bir yorum yönergesi yerleştirirsiniz ve go generate komutunu çalıştırmak belirtilen aracı yürütür:
//go:generate stringer -type=Status
type Status int
const (
Pending Status = iota
Active
Completed
)go generate ./... komutunu çalıştırmak, stringer aracını çağırır; bu araç Status türü için bir String() yöntemi içeren yeni bir dosya oluşturur. Oluşturulan kod, programınızla birlikte derlenen normal Go kodudur.
Go ekosistemindeki yaygın kod oluşturma araçları arasında enum dize yöntemleri için stringer, arayüzlerden test mock'ları oluşturmak için mockgen ve Protocol Buffer tanımlarından kod oluşturmak için protoc bulunur. Birçok ORM ve API çerçevesi de tür güvenli veritabanı sorguları veya istemci kodu oluşturmak için kod oluşturmayı kullanır.
Yansıtmaya göre temel avantaj, oluşturulan kodun derleyici tarafından denetlenmesidir. Hatalar çalışma zamanında değil, derleme sırasında yakalanır. Bunun karşılığında ek bir derleme adımı ve deponuzda yönetmeniz gereken oluşturulmuş dosyalar gelir. Birçok tür arasında tekrarlanan uygulamalar gerektiren OOP kalıpları için kod oluşturma, genellikle güvenlik ve kolaylık arasında en iyi dengeyi sağlar.
Görev
KolayEnum benzeri türler için String() yöntemleri oluşturan bir kod üreticisi geliştirelim! Bu ortamda gerçek go generate komutunu çalıştıramasak da, kod üretim araçlarının yaptığını simüle edeceksin: tür tanımlarına göre program aracılığıyla Go kaynak kodu üreteceksin.
Kodunu iki dosyaya ayıracaksın:
generator.go: Kod üretim mantığını oluştur.Bir
EnumTypeyapısı oluştur. Bu yapı, birName(string) ve sabit adlarını temsil eden birValues(string dilimi) ile enum benzeri bir tür tanımını temsil etsin.Bir
GenerateStringMethod(e EnumType) stringişlevi oluştur. Bu işlev, birString()yöntemi için Go kaynak kodu üretsin. Üretilen kod aşağıdaki kalıbı izlemelidir:func (e TypeName) String() string { switch e { case Value1: return "Value1" case Value2: return "Value2" default: return "Unknown" } }Ayrıca
GenerateConstants(e EnumType) stringkullanarak sabit bildirimlerini üreten biriotaişlevi oluştur:const ( Value1 TypeName = iota Value2 Value3 )Son olarak, her iki çıktıyı da bunun üretilmiş kod olduğunu belirten bir başlık yorumuyla birleştiren
GenerateFullCode(e EnumType) stringişlevini oluştur:// Code generated by enum generator. DO NOT EDIT. [constants] [string method]main.go: Farklı enum türleri için kod üretmek üzere üreticini kullan.Enum türünün adını, ardından değerlerin sayısını ve her bir değer adını oku. Bu bilgileri üreticine aktar ve üretilen kodun tamamını yazdır.
Aşağıdaki girdiler sağlanacaktır:
- 1. satır: Enum türünün adı
- 2. satır: Değerlerin sayısı
- Sonraki satırlar: Her bir değer adı
Örneğin, şu girdi verildiğinde:
Status
3
Pending
Active
CompletedÇıktın şu olmalıdır:
// 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"
}
}Ve şu girdi verildiğinde:
Priority
2
Low
HighÇıktın şu olmalıdır:
// 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"
}
}Bu alıştırma, stringer gibi araçların arkasındaki temel kavramı gösterir: çalışma zamanında reflection kullanmak yerine, tekrarlı ancak tür güvenli kodu derleme zamanında üretmek. Üreticin, bir dosyaya kaydedilebilecek ve bir projenin geri kalanıyla birlikte derlenebilecek geçerli Go kodu üretir.
Kendin dene
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Enum tür adını oku
typeName, _ := reader.ReadString('\n')
typeName = strings.TrimSpace(typeName)
// Değer sayısını oku
countStr, _ := reader.ReadString('\n')
count, _ := strconv.Atoi(strings.TrimSpace(countStr))
// Her bir değer adını oku
values := make([]string, count)
for i := 0; i < count; i++ {
value, _ := reader.ReadString('\n')
values[i] = strings.TrimSpace(value)
}
// TODO: Okunan verilerle bir EnumType oluştur
// TODO: GenerateFullCode kullanarak tam kodu oluştur ve yazdır
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Nesne Yönelimli Programlama bölümündeki tüm dersler
1Go OOP Temelleri
Harici DosyalarGo Çalışma Alanı ve ModüllerPaketler ve İçe AktarmalarDışa Aktarılan ve Aktarılmayan İsimlerGo'da OOP'ye GirişSınıf Olarak Struct'larStruct'larda Metot TanımlamaPointer ve Değer AlıcılarStruct BaşlatmaYapıcı FonksiyonlarÖzet - Basit Hesap Makinesi4Arayüzler
Arayüzlere GirişÖrtük UygulamaSözleşme Olarak ArayüzBoş Arayüz (any)Tür OnaylamaTür SeçimiArayüz BileşimiStringer ve Error ArayüzleriÖzet - Şekil Hesaplayıcı7Kapsülleme
Dışa Aktarılan ve Aktarılmayan AlanlarPaket Seviyesinde KapsüllemeGetter ve Setter MetotlarıGo'da Bilgi GizlemeÖzet - Öğrenci Kayıtları10Generics (Go 1.18+)
Generics'e GirişTür ParametreleriTür KısıtlamalarıGeneric Struct'larGeneric Metotlar İçin Geçici ÇözümÖzet - Generic Koleksiyon13Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıAbstract Factory KalıbıObserver KalıbıStrategy Kalıbı2Türler ve Struct'lar: Derinlemesine İnceleme
Temel ve Bileşik TürlerÖzel Tür TanımlamalarıStruct EtiketleriAnonim Struct'larİç İçe Geçmiş Struct'larSıfır Değerler ve VarsayılanlarÖzet - Rehber5Kalıtım Yerine Kompozisyon
Go'da Neden Kalıtım YokStruct Gömme TemelleriMetot YükseltmeBirden Fazla Struct GömmeGömme vs AgregasyonGömülü Metotları GölgelemeÖzet - Çalışan Hiyerarşisi8Hata Yönetimi ve OOP
error ArayüzüÖzel Hata TürleriHata Sarmalama (fmt.Errorf)Sentinel Hatalarerrors.Is() ve errors.As()Panic, Defer ve RecoverÖzet - Dosya Ayrıştırıcı3İşaretçiler ve Bellek
Go'da İşaretçi TemelleriStruct İşaretçileriDeğer ile Geçme ve Referans ile Geçmenew() FonksiyonuGo'da Garbage CollectionÖzet - Linked List Oluşturucu6Go'da Polimorfizm
Interface'ler ile PolimorfizmGo'da Duck TypingInterface Karşılama KurallarıPolimorfik KoleksiyonlarDependency InjectionÖzet - Payment Processor9Eşzamanlılık ve OOP
Goroutine TemelleriKanallar ve İletişimTamponlu ve Tamponsuz KanallarSelect İfadesisync.Mutex ve sync.RWMutexsync.WaitGroupThread-Safe Struct TasarımıÖzet - Worker Pool12İleri Düzey OOP Kavramları
Functional Options DeseniGo'da Builder DeseniMetot ZincirlemeTür Takma Adları vs. TanımlamalarReflection TemelleriKod Üretimine Genel BakışKendi başına pratik yap: Online Go derleyicisi