Go 已成為現代後端開發、雲端服務和 DevOps 工具的強大力量。讓我們探索如何編寫慣用的 Go 程式碼來利用該語言的優勢。
首先,讓我們建立一個現代的 Go 專案架構:
# Initialize a new module go mod init myproject # Project structure myproject/ ├── cmd/ │ └── api/ │ └── main.go ├── internal/ │ ├── handlers/ │ ├── models/ │ └── services/ ├── pkg/ │ └── utils/ ├── go.mod └── go.sum
這是一個結構良好的 Go 程式的範例:
package main import ( "context" "log" "net/http" "os" "os/signal" "syscall" "time" ) // Server configuration type Config struct { Port string ReadTimeout time.Duration WriteTimeout time.Duration ShutdownTimeout time.Duration } // Application represents our web server type Application struct { config Config logger *log.Logger router *http.ServeMux } // NewApplication creates a new application instance func NewApplication(cfg Config) *Application { logger := log.New(os.Stdout, "[API] ", log.LstdFlags) return &Application{ config: cfg, logger: logger, router: http.NewServeMux(), } } // setupRoutes configures all application routes func (app *Application) setupRoutes() { app.router.HandleFunc("/health", app.healthCheckHandler) app.router.HandleFunc("/api/v1/users", app.handleUsers) } // Run starts the server and handles graceful shutdown func (app *Application) Run() error { // Setup routes app.setupRoutes() // Create server srv := &http.Server{ Addr: ":" + app.config.Port, Handler: app.router, ReadTimeout: app.config.ReadTimeout, WriteTimeout: app.config.WriteTimeout, } // Channel to listen for errors coming from the listener. serverErrors := make(chan error, 1) // Start the server go func() { app.logger.Printf("Starting server on port %s", app.config.Port) serverErrors <- srv.ListenAndServe() }() // Listen for OS signals shutdown := make(chan os.Signal, 1) signal.Notify(shutdown, os.Interrupt, syscall.SIGTERM) // Block until we receive a signal or an error select { case err := <-serverErrors: return fmt.Errorf("server error: %w", err) case <-shutdown: app.logger.Println("Starting shutdown...") // Create context for shutdown ctx, cancel := context.WithTimeout( context.Background(), app.config.ShutdownTimeout, ) defer cancel() // Gracefully shutdown the server err := srv.Shutdown(ctx) if err != nil { return fmt.Errorf("graceful shutdown failed: %w", err) } } return nil }
Go 的介面系統和錯誤處理是關鍵特性:
// UserService defines the interface for user operations type UserService interface { GetUser(ctx context.Context, id string) (*User, error) CreateUser(ctx context.Context, user *User) error UpdateUser(ctx context.Context, user *User) error DeleteUser(ctx context.Context, id string) error } // Custom error types type NotFoundError struct { Resource string ID string } func (e *NotFoundError) Error() string { return fmt.Sprintf("%s with ID %s not found", e.Resource, e.ID) } // Implementation type userService struct { db *sql.DB logger *log.Logger } func (s *userService) GetUser(ctx context.Context, id string) (*User, error) { user := &User{} err := s.db.QueryRowContext( ctx, "SELECT id, name, email FROM users WHERE id = ", id, ).Scan(&user.ID, &user.Name, &user.Email) if err == sql.ErrNoRows { return nil, &NotFoundError{Resource: "user", ID: id} } if err != nil { return nil, fmt.Errorf("querying user: %w", err) } return user, nil }
Go 的 goroutine 和通道讓並發程式設計變得簡單:
// Worker pool pattern func processItems(items []string, numWorkers int) error { jobs := make(chan string, len(items)) results := make(chan error, len(items)) // Start workers for w := 0; w < numWorkers; w++ { go worker(w, jobs, results) } // Send jobs to workers for _, item := range items { jobs <- item } close(jobs) // Collect results for range items { if err := <-results; err != nil { return err } } return nil } func worker(id int, jobs <-chan string, results chan<- error) { for item := range jobs { results <- processItem(item) } } // Rate limiting func rateLimiter[T any](input <-chan T, limit time.Duration) <-chan T { output := make(chan T) ticker := time.NewTicker(limit) go func() { defer close(output) defer ticker.Stop() for item := range input { <-ticker.C output <- item } }() return output }
Go 擁有出色的內建測試支援:
// user_service_test.go package service import ( "context" "testing" "time" ) func TestUserService(t *testing.T) { // Table-driven tests tests := []struct { name string userID string want *User wantErr bool }{ { name: "valid user", userID: "123", want: &User{ ID: "123", Name: "Test User", }, wantErr: false, }, { name: "invalid user", userID: "999", want: nil, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { svc := NewUserService(testDB) got, err := svc.GetUser(context.Background(), tt.userID) if (err != nil) != tt.wantErr { t.Errorf("GetUser() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { t.Errorf("GetUser() = %v, want %v", got, tt.want) } }) } } // Benchmarking example func BenchmarkUserService_GetUser(b *testing.B) { svc := NewUserService(testDB) ctx := context.Background() b.ResetTimer() for i := 0; i < b.N; i++ { _, _ = svc.GetUser(ctx, "123") } }
Go 可以輕鬆分析和最佳化程式碼:
// Use sync.Pool for frequently allocated objects var bufferPool = sync.Pool{ New: func() interface{} { return new(bytes.Buffer) }, } func processRequest(data []byte) string { buf := bufferPool.Get().(*bytes.Buffer) defer bufferPool.Put(buf) buf.Reset() buf.Write(data) // Process data... return buf.String() } // Efficiently handle JSON type User struct { ID string `json:"id"` Name string `json:"name"` Email string `json:"email"` CreatedAt time.Time `json:"created_at"` } func (u *User) MarshalJSON() ([]byte, error) { type Alias User return json.Marshal(&struct { *Alias CreatedAt string `json:"created_at"` }{ Alias: (*Alias)(u), CreatedAt: u.CreatedAt.Format(time.RFC3339), }) }
Go 的簡單性和強大的功能使其成為現代開發的絕佳選擇。重點:
Go 開發的哪些方面您最感興趣?在下面的評論中分享您的經驗!
以上是掌握 Go:現代 Golang 開發實用指南的詳細內容。更多資訊請關注PHP中文網其他相關文章!