Menu
Coddy logo textTech

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.

challenge icon

Görev

Kolay

Enum 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 EnumType yapısı oluştur. Bu yapı, bir Name (string) ve sabit adlarını temsil eden bir Values (string dilimi) ile enum benzeri bir tür tanımını temsil etsin.

    Bir GenerateStringMethod(e EnumType) string işlevi oluştur. Bu işlev, bir String() 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) string kullanarak sabit bildirimlerini üreten bir iota iş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) string iş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
}
quiz iconKendini test et

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

Kendi başına pratik yap: Online Go derleyicisi