🐹 Go

Go 语言入门

Go (Golang) для начинающих: язык Google для облаков и серверов

Добро пожаловать в мир Go! Если ты хочешь создавать быстрые серверы, облачные сервисы и инструменты командной строки — Go создан именно для этого. Молодой, простой и невероятно производительный язык от Google.

История Go: как Google создал новый язык

Представь себе 2007 год. В Google работают тысячи программистов. Они пишут на C++ и Java, но сталкиваются с проблемами: C++ компилируется долго, Java перегружена. Три выдающихся инженера решают создать что-то новое:

  • Роберт Гриземер — работал над JavaScript-движком V8 (в Chrome)
  • Роб Пайк — создатель операционной системы Plan 9, легенда Unix
  • Кен Томпсон — создатель языка C и операционной системы Unix. Без него не было бы ни Linux, ни macOS!

В 2009 году Google анонсировал Go. В 2012 году вышла стабильная версия 1.0. Сегодня это один из самых востребованных языков в облачной разработке.

Философия Go: простота превыше всего

Создатели поставили цель: язык должен быть радикально простым. Принципы Go:

  • Минимализм — мало ключевых слов, нет классов, нет исключений, нет перегрузки операторов
  • Явность — код читается буквально, никакой магии
  • Быстрая компиляция — секунды даже в больших проектах
  • Встроенная конкурентность — горутины и каналы встроены в язык

Где используется Go

🐳 Docker и Kubernetes

Docker и Kubernetes — оба написаны на Go. Это два важнейших инструмента современной облачной разработки.

🌐 Backend-серверы

Google, Uber, Dropbox, Twitch используют Go для своих серверов. Go обрабатывает миллионы запросов в секунду с минимальными ресурсами.

🛠️ CLI-инструменты

Hugo (генератор сайтов), Terraform (инфраструктура как код), CockroachDB написаны на Go.

Установка Go

# Проверка установки
go version
# go version go1.22.0 linux/amd64

# Создать проект
mkdir hello-go && cd hello-go
go mod init hello

Первая программа

Создай файл main.go:

package main

import "fmt"

func main() {
    fmt.Println("Привет, мир!")
}

Запускаем:

go run main.go
# Привет, мир!

Разбор каждой строки

  • package main — каждый файл Go принадлежит пакету. Пакет main — это исполняемая программа.
  • import "fmt" — импортируем пакет fmt (format) для ввода-вывода.
  • func main() { — точка входа. С этой функции всё начинается.
  • fmt.Println("Привет, мир!") — выводим строку с переводом строки в конце.
  • } — В Go открывающая скобка ВСЕГДА на той же строке, иначе ошибка!

Пакет fmt: форматированный вывод

package main

import "fmt"

func main() {
    // Println — вывод со знаком новой строки
    fmt.Println("Строка 1")
    fmt.Println("Строка 2")

    // Print — без новой строки
    fmt.Print("Без ")
    fmt.Print("переноса ")
    fmt.Println("строки")

    // Printf — форматированный вывод
    name := "Дима"
    age := 16
    fmt.Printf("Меня зовут %s, мне %d лет\n", name, age)

    // Sprintf — форматирование в строку (не вывод)
    message := fmt.Sprintf("Привет, %s!", name)
    fmt.Println(message)

    // Основные форматы:
    fmt.Printf("%d\n", 42)       // целое число
    fmt.Printf("%f\n", 3.14)     // число с плавающей точкой
    fmt.Printf("%.2f\n", 3.14159) // 2 знака после запятой
    fmt.Printf("%s\n", "строка")  // строка
    fmt.Printf("%t\n", true)      // булево
    fmt.Printf("%v\n", 42)        // любой тип (универсальный)
    fmt.Printf("%T\n", 42)        // тип переменной
}

Ввод от пользователя

package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
)

func main() {
    reader := bufio.NewReader(os.Stdin)
    
    fmt.Print("Как тебя зовут? ")
    name, _ := reader.ReadString('\n')
    name = strings.TrimSpace(name)
    
    fmt.Printf("Привет, %s! Добро пожаловать в Go!\n", name)
    
    // Простой ввод числа
    var age int
    fmt.Print("Сколько тебе лет? ")
    fmt.Scan(&age)  // & — адрес переменной (указатель)
    
    fmt.Printf("Тебе %d лет\n", age)
}

Структура Go-проекта

my-project/
├── go.mod          # Описание модуля и зависимостей
├── go.sum          # Контрольные суммы зависимостей
├── main.go         # Основной файл (точка входа)
├── utils/
│   └── helpers.go  # Вспомогательные функции
└── models/
    └── user.go     # Модели данных
// go.mod выглядит так:
module hello

go 1.22

Типичные ошибки новичков

Ошибка 1: Импорт без использования

// ОШИБКА! Go не компилируется если импорт не используется
import "fmt"
import "math"  // Ошибка если math нигде не используется

// ПРАВИЛЬНО: удали неиспользуемые импорты
import "fmt"

Ошибка 2: Переменная без использования

func main() {
    x := 5  // ОШИБКА! 'x' declared but not used
    fmt.Println("hello")
    
    // ПРАВИЛЬНО:
    x := 5
    fmt.Println(x)
}

Ошибка 3: Открывающая скобка на новой строке

// ОШИБКА синтаксиса!
func main()
{
    fmt.Println("hello")
}

// ПРАВИЛЬНО: скобка на той же строке
func main() {
    fmt.Println("hello")
}

Команды go tool

go run main.go      # Запустить без компиляции
go build            # Скомпилировать
go build -o app     # Скомпилировать с именем 'app'
go test ./...       # Запустить тесты
go fmt ./...        # Отформатировать код
go vet ./...        # Проверить код на ошибки
go mod tidy         # Обновить зависимости

Итого

  • ✅ Go создан в Google в 2009 году Робертом Гриземером, Робом Пайком и Кеном Томпсоном
  • ✅ Go используется в Docker, Kubernetes, backend-серверах и CLI-инструментах
  • ✅ Философия Go: простота, явность, скорость компиляции
  • ✅ Каждая программа начинается с package main и функции func main()
  • ✅ fmt.Println — вывод строки, fmt.Printf — форматированный вывод
  • ✅ В Go нельзя импортировать пакеты или объявлять переменные, которые не используются
  • ✅ Открывающая фигурная скобка всегда на той же строке

Разбор каждой строки программы

package main  // (1)

import "fmt"  // (2)

func main() { // (3)
    fmt.Println("Привет, мир!") // (4)
} // (5)
  • (1) package main — каждый файл Go принадлежит пакету. main — специальный пакет для исполняемых программ. Пакет — это как папка с кодом.
  • (2) import "fmt" — импортируем пакет fmt (format). Это стандартная библиотека для форматированного ввода-вывода. В Go нельзя импортировать что-то и не использовать — получишь ошибку компиляции!
  • (3) func main() { — объявляем функцию main. Это точка входа программы. Открывающая скобка ОБЯЗАНА быть на той же строке — иначе синтаксическая ошибка!
  • (4) fmt.Println("Привет, мир!") — вызываем функцию Println из пакета fmt. Она выводит строку и добавляет символ новой строки.
  • (5) } — закрывающая скобка функции.

Пакет fmt: все способы вывода

package main

import "fmt"

func main() {
    name := "Дима"
    age  := 16
    gpa  := 4.75

    // Println — вывод со знаком новой строки
    fmt.Println("Привет!")
    fmt.Println(name, age, gpa) // Пробелы между значениями автоматически

    // Print — вывод без новой строки
    fmt.Print("Без ")
    fmt.Print("переноса")
    fmt.Println()  // Просто новая строка

    // Printf — форматированный вывод
    fmt.Printf("Меня зовут %s, мне %d лет, GPA: %.2f\n", name, age, gpa)

    // Основные форматные спецификаторы:
    fmt.Printf("%d\n",   42)        // Целое число
    fmt.Printf("%f\n",   3.14)      // Число с точкой
    fmt.Printf("%.2f\n", 3.14159)   // 2 знака после точки: 3.14
    fmt.Printf("%s\n",   "строка")  // Строка
    fmt.Printf("%q\n",   "строка")  // Строка в кавычках: "строка"
    fmt.Printf("%t\n",   true)      // Булево: true/false
    fmt.Printf("%v\n",   42)        // Любой тип (универсальный)
    fmt.Printf("%T\n",   42)        // Тип переменной: int
    fmt.Printf("%b\n",   10)        // Двоичное: 1010
    fmt.Printf("%x\n",   255)       // Шестнадцатеричное: ff
    fmt.Printf("%05d\n", 42)        // Ширина 5, с нулями: 00042

    // Sprintf — форматирование в строку
    msg := fmt.Sprintf("Пользователь %s (%d лет)", name, age)
    fmt.Println(msg)  // Пользователь Дима (16 лет)
}

Ввод от пользователя

package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
    "strings"
)

func main() {
    reader := bufio.NewReader(os.Stdin)

    // Ввод строки
    fmt.Print("Как тебя зовут? ")
    name, _ := reader.ReadString('\n')
    name = strings.TrimSpace(name)  // Убираем пробелы и \n

    fmt.Printf("Привет, %s!\n", name)

    // Ввод числа
    fmt.Print("Сколько тебе лет? ")
    ageStr, _ := reader.ReadString('\n')
    ageStr = strings.TrimSpace(ageStr)
    age, err := strconv.Atoi(ageStr)
    if err != nil {
        fmt.Println("Ошибка: введи число!")
        return
    }

    fmt.Printf("Тебе %d лет.\n", age)
    if age >= 18 {
        fmt.Println("Ты совершеннолетний!")
    } else {
        fmt.Printf("До 18 лет осталось %d лет.\n", 18 - age)
    }
}

Структура Go-проекта

my-project/
├── go.mod          # Описание модуля и зависимостей
├── go.sum          # Контрольные суммы (автогенерируется)
├── main.go         # Точка входа программы
├── utils/
│   └── helpers.go  # Вспомогательные функции
└── models/
    └── user.go     # Модели данных
// go.mod — файл модуля
module github.com/myuser/my-project

go 1.22

require (
    github.com/gin-gonic/gin v1.9.0  // внешняя зависимость
)

Go Modules: управление зависимостями

# Инициализировать модуль
go mod init github.com/myname/myproject

# Добавить зависимость
go get github.com/gin-gonic/gin

# Обновить зависимости
go mod tidy

# Список зависимостей
go list -m all

Полезные команды go tool

go run main.go        # Запустить без компиляции (для разработки)
go build              # Скомпилировать в текущей папке
go build -o myapp     # Скомпилировать с именем 'myapp'
go test ./...         # Запустить все тесты
go fmt ./...          # Отформатировать весь код (ОБЯЗАТЕЛЬНО!)
go vet ./...          # Статический анализатор — находит ошибки
go doc fmt.Println    # Документация функции
go env                # Показать переменные окружения Go
go clean              # Удалить скомпилированные файлы

Типичные ошибки новичков

Ошибка 1: Неиспользуемый импорт

import "fmt"
import "math"  // ОШИБКА если math нигде не используется!

// ПРАВИЛЬНО: удали неиспользуемые импорты
// В VS Code с расширением Go это делается автоматически

Ошибка 2: Объявленная переменная не используется

func main() {
    x := 5          // ОШИБКА: x declared and not used
    fmt.Println("hi")
}

// ПРАВИЛЬНО:
func main() {
    x := 5
    fmt.Println(x)  // Используем x
}

Ошибка 3: Скобка на новой строке

// ОШИБКА синтаксис!
func main()
{
    fmt.Println("hi")
}

// ПРАВИЛЬНО: открывающая скобка на той же строке
func main() {
    fmt.Println("hi")
}

Ошибка 4: Неправильное присваивание nil

var x int = nil   // ОШИБКА! int не может быть nil
var p *int = nil  // OK — указатель может быть nil
var s []int = nil // OK — срез может быть nil

Почему Go так популярен: сравнение

Чем Go отличается от других языков:

  • Go vs Python: Go в 10-100 раз быстрее, компилируемый, статически типизированный. Python проще для начала, но медленнее.
  • Go vs Java: Go быстрее компилируется, занимает меньше памяти, нет JVM. Java богаче экосистемой.
  • Go vs C++: Go значительно проще, безопаснее (сборщик мусора), быстрее компилируется. C++ быстрее в критичных по производительности местах.
  • Go vs Rust: Go проще в изучении, Rust безопаснее по памяти (без сборщика мусора).

Итого

  • ✅ Go создан в Google в 2009 году Гриземером, Пайком и Томпсоном
  • ✅ Используется в Docker, Kubernetes, backend-серверах, DevOps инструментах
  • ✅ Философия: простота, явность, скорость компиляции
  • ✅ Каждый файл начинается с package
  • ✅ Точка входа — func main() в пакете main
  • ✅ fmt.Println — вывод строки, fmt.Printf — форматированный вывод
  • ✅ Нельзя импортировать неиспользуемые пакеты
  • ✅ Нельзя объявлять неиспользуемые переменные
  • ✅ Открывающая скобка — только на той же строке что и заголовок функции
  • ✅ go run — запустить, go build — скомпилировать, go fmt — форматировать

Стандартная библиотека Go

package main

import (
    "fmt"
    "math"
    "sort"
    "strings"
    "time"
    "unicode"
)

func main() {
    // math — математика
    fmt.Printf("Pi: %.5f\n", math.Pi)
    fmt.Printf("Sqrt(2): %.5f\n", math.Sqrt(2))
    fmt.Printf("Pow(2,10): %.0f\n", math.Pow(2, 10))
    fmt.Printf("Abs(-42): %.0f\n", math.Abs(-42))
    
    // strings — работа со строками
    s := "  Привет, Мир!  "
    fmt.Println(strings.TrimSpace(s))          // Привет, Мир!
    fmt.Println(strings.ToUpper(s))            // всё заглавными
    fmt.Println(strings.Contains(s, "Мир"))    // true
    fmt.Println(strings.Replace(s, "Мир", "Go", 1))
    parts := strings.Split("a,b,c", ",")
    fmt.Println(parts)                          // [a b c]
    fmt.Println(strings.Join(parts, " - "))    // a - b - c
    
    // unicode — работа с символами
    fmt.Println(unicode.IsLetter('А'))  // true
    fmt.Println(unicode.IsDigit('5'))   // true
    
    // sort — сортировка
    nums := []int{5, 2, 8, 1, 9, 3}
    sort.Ints(nums)
    fmt.Println(nums)  // [1 2 3 5 8 9]
    
    words := []string{"Ялта", "Москва", "Астрахань"}
    sort.Strings(words)
    fmt.Println(words)  // [Астрахань Москва Ялта]
    
    // time — дата и время
    now := time.Now()
    fmt.Println(now.Format("02.01.2006 15:04:05"))
    tomorrow := now.Add(24 * time.Hour)
    fmt.Println(tomorrow.Format("02.01.2006"))
}