Приведите примеры кода на Go, демонстрирующие базовые возможности языка для бэкенд-разработки.

Ответ

Конечно, вот несколько классических примеров, которые часто встречаются в бэкенд-разработке на Go.

1. Простой HTTP-сервер

Это базовый пример для любого веб-сервиса. Он показывает, как запустить сервер и обработать входящий HTTP-запрос.

package main

import (
    "fmt"
    "log"
    "net/http"
)

// handler обрабатывает запросы к корневому URL "/".
func handler(w http.ResponseWriter, r *http.Request) {
    // Fprintf записывает форматированную строку в ResponseWriter.
    fmt.Fprintf(w, "Привет, мир! Это мой первый веб-сервер на Go.")
}

func main() {
    // Регистрируем наш обработчик для всех запросов к "/".
    http.HandleFunc("/", handler)

    // Запускаем сервер на порту 8080.
    // ListenAndServe блокирует выполнение, пока сервер работает.
    fmt.Println("Сервер запущен на http://localhost:8080")
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        log.Fatal("Ошибка запуска сервера: ", err)
    }
}

2. Конкурентная обработка задач (Worker Pool)

Этот пример демонстрирует мощь горутин и каналов для параллельного выполнения задач. Паттерн Worker Pool очень популярен для обработки фоновых задач, например, отправки email или обработки изображений.

package main

import (
    "fmt"
    "sync"
    "time"
)

// worker — это горутина, которая получает задачи из канала `jobs`
// и отправляет результат в канал `results`.
func worker(id int, wg *sync.WaitGroup, jobs <-chan int, results chan<- int) {
    defer wg.Done() // Сообщаем WaitGroup, что воркер завершил работу

    for j := range jobs {
        fmt.Printf("Воркер %d начал задачу %dn", id, j)
        time.Sleep(time.Second) // Имитация долгой работы
        results <- j * 2
        fmt.Printf("Воркер %d закончил задачу %dn", id, j)
    }
}

func main() {
    const numJobs = 5
    jobs := make(chan int, numJobs)
    results := make(chan int, numJobs)

    var wg sync.WaitGroup

    // Запускаем 3 воркера
    for w := 1; w <= 3; w++ {
        wg.Add(1) // Увеличиваем счетчик WaitGroup
        go worker(w, &wg, jobs, results)
    }

    // Отправляем 5 задач в канал jobs
    for j := 1; j <= numJobs; j++ {
        jobs <- j
    }
    close(jobs) // Закрываем канал, чтобы воркеры завершились после выполнения всех задач

    // Ждем, пока все воркеры завершат свою работу
    wg.Wait()

    // Закрываем канал с результатами, так как больше записей не будет
    close(results)

    // Собираем результаты
    for r := range results {
        fmt.Println("Получен результат:", r)
    }
}