April 30

Golang для новичков: основные понятия и примеры кода

Go (или Golang) — это язык программирования, созданный в Google. Go прост, быстр, идеально подходит для создания микросервисов, API, командных утилит и сетевых приложений.

Эта статья быстро познакомит тебя с основами Go и позволит за несколько минут написать своё первое приложение.


🔹 Почему Go?

Golang имеет ряд важных преимуществ:

  • Простота: понятный синтаксис, похожий на C и Python.
  • 🚀 Скорость: высокая производительность и быстрая компиляция.
  • 🔄 Параллелизм: простая и эффективная работа с потоками через goroutines.
  • 📦 Удобные модули: встроенный менеджер зависимостей.
  • 🛠 Кроссплатформенность: легко собирать приложения под Windows, Linux и macOS.

📌 Установка Go

  1. Скачай последнюю версию Go отсюда (выбирай версию для своей ОС).
  2. Установи и проверь в терминале:
go version

Если увидишь версию, значит всё получилось 🎉.

🧑‍💻 Первая программа на Go

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

package main

import "fmt"

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

Запусти код из терминала:

go run hello.go

Или скомпилируй приложение:

go build hello.go
./hello

🚀 Что произошло сейчас?

Ты только что написал и запустил свою первую программу на Go. Но давай кратко разберёмся, что именно произошло:

  1. Ты создал файл с расширением .go, где указал, что это будет пакет main. 📌 В Go приложение всегда стартует с функции main() из пакета main.
  2. Ты импортировал стандартную библиотеку fmt (от слова format) — одну из самых часто используемых в Go библиотек для работы с текстом и выводом данных.
  3. Написал функцию main(), из которой Go начинает выполнение программы.
  4. Использовал функцию fmt.Println() — она выводит текст на экран и автоматически добавляет перевод строки.

Когда ты написал команду go run hello.go, произошло следующее:

  • Go-компилятор скомпилировал твой код в памяти.
  • Полученный код был тут же запущен.
  • Ты увидел результат выполнения — сообщение Привет, мир!.

Если же ты использовал команду go build hello.go, то Go-компилятор создал исполняемый файл (бинарник), который можно запускать отдельно — и он будет работать даже без установленного Go.

💡 И это круто: программы на Go всегда компилируются в исполняемые файлы, которые легко распространять и запускать на любой платформе без дополнительных зависимостей!

Теперь можно двигаться дальше и познакомиться с основами синтаксиса Go.

🧩 Основы синтаксиса

Переменные и типы данных:

var name string = "Вася"
age := 30 // короткое объявление переменной
fmt.Println("Имя:", name, "Возраст:", age)

Часто задаваемые вопросы:

🔸 Какая разница между fmt.Print и fmt.Println?

  • fmt.Print() выводит текст ровно таким, каким вы его указали — без переноса строки в конце.
  • fmt.Println() автоматически добавляет перевод строки (\n) после каждого вызова.

🔸 Чем отличаются := и = в Go?

  • := используется для короткого объявления переменной с автоматическим выводом типа.
age := 25 // Go автоматически определит тип как int

Функции:

func add(x int, y int) int {
    return x + y
}

result := add(10, 5)
fmt.Println("Результат:", result)

Условия и циклы:

if age > 18 {
    fmt.Println("Взрослый")
} else {
    fmt.Println("Ещё ребёнок")
}

// цикл for
for i := 0; i < 5; i++ {
    fmt.Println(i)
}

Структуры (structs) в Go — это удобный способ объединения данных в одну логическую сущность. Структура позволяет создать собственный тип, состоящий из нескольких полей, каждое из которых может иметь свой тип данных. Структуры помогают организовать данные и делают код более читабельным и простым для поддержки. Например, ты можешь создать структуру Person, которая будет хранить имя, возраст и профессию, и использовать её, чтобы легко передавать данные о человеке между функциями. В отличие от классов в других языках, структуры в Go не поддерживают наследование, но ты можешь добавлять к ним методы, что делает их удобным аналогом классов для организации логики и данных в твоём приложении.

Вот наглядный и понятный пример использования структур в Go с пояснениями:

package main

import "fmt"

// Определяем структуру Person с несколькими полями разных типов
type Person struct {
	Name     string
	Age      int
	Job      string
}

// Метод структуры Person, выводящий информацию о человеке
func (p Person) Introduce() {
	fmt.Printf("Привет, я %s, мне %d лет, и я работаю %s.\n", p.Name, p.Age, p.Job)
}

func main() {
	// Создание экземпляра структуры Person
	person := Person{
		Name: "Алиса",
		Age:  28,
		Job:  "разработчиком на Go",
	}

	// Вызов метода структуры
	person.Introduce()

	// Доступ к отдельным полям структуры
	fmt.Println("Имя человека:", person.Name)
	fmt.Println("Возраст человека:", person.Age)
}

Пояснения к примеру:

  • Структура объявляется с помощью ключевого слова type.
  • Поля структуры задаются внутри фигурных скобок {} с указанием типа.
  • Метод привязывается к структуре через (p Person) перед его названием, где p — это имя переменной структуры.
  • Создание структуры возможно как сразу с полями (Person{}), так и пустой структуры с последующим заполнением полей отдельно.
  • Для вызова метода используется стандартный синтаксис: person.Introduce().

🔀 Горутины и параллелизм (кратко)

В Go легко запускать параллельные задачи, которые реализованы в виде горутин (goroutine):

package main

import (
    "fmt"
    "time"
)

func task(name string) {
    for i := 0; i < 3; i++ {
        fmt.Println("Задача", name, "итерация", i)
        time.Sleep(time.Second)
    }
}

func main() {
    go task("A") // запускается параллельно
    go task("B") // тоже параллельно
    time.Sleep(4 * time.Second)
}

Запусти код, и увидишь, как задачи выполняются одновременно. Разберем горутины подробнее.

🔸 Что такое горутина (goroutine)?

Горутина (goroutine) — это облегчённый поток, который позволяет выполнять код параллельно и асинхронно в рамках одного приложения.

Создаётся добавлением слова go перед вызовом функции:

go myFunction() // запустится параллельно с основной программой

Горутины — это очень лёгкие и дешёвые потоки. Ты можешь запустить тысячи горутин, и приложение будет работать эффективно и быстро.

📦 Пакеты и модули

Go управляет зависимостями через модули. Инициализируем новый модуль так:

go mod init myproject

Добавим библиотеку (например, популярный веб-фреймворк Gin):

go get github.com/gin-gonic/gin

Используем ее в коде:

package main

import "github.com/gin-gonic/gin"

func main() {
    r := gin.Default()
    r.GET("/", func(c *gin.Context) {
        c.JSON(200, gin.H{"message": "Привет от Gin!"})
    })
    r.Run(":8080")
}

Ура! Мы запустили простое веб-приложение на Go!

🐾 Советы начинающим

  • Изучай стандартную библиотеку — она очень мощная.
  • Изучай простые проекты на GitHub, чтобы понять структуру приложений.
  • Пиши много маленьких программ — Go отлично подходит для CLI-утилит.

Часто задаваемые вопросы

🔸 Почему Go — компилируемый язык, но так быстро собирается?

Go был специально разработан для быстрого компилирования, поэтому:

  • компилятор Go эффективен и оптимизирован для скорости;
  • в языке сознательно ограничено количество сложных конструкций, которые могли бы замедлить компиляцию;
  • программы компилируются сразу в нативный код, что делает их выполнение быстрым, а сами бинарники — компактными.

🔸 Есть ли в Go классы?

Нет. В Go нет понятия классов в привычном понимании (как, например, в Java или C++). Но ты можешь использовать структуры (struct) и методы для них, чтобы организовывать код подобно классам.

🔸 Что такое generics (обобщения) и есть ли они в Go?

Generics (обобщения) — это механизм, который позволяет создавать функции и структуры, работающие с любыми типами данных, не привязываясь к конкретному типу.

Обобщения были добавлены в Go начиная с версии 1.18:

package main

import "fmt"

// Generic-функция, которая работает с любыми типами
func PrintSlice[T any](s []T) {
	for _, v := range s {
		fmt.Println(v)
	}
}

func main() {
	intSlice := []int{1, 2, 3}
	strSlice := []string{"a", "b", "c"}

	PrintSlice(intSlice) // работает с числами
	PrintSlice(strSlice) // работает со строками
}

Таким образом, одна функция может быть универсальной и использоваться с разными типами данных без повторения кода.

🔸 Есть ли в Go обработка исключений (try/catch)?

В Go нет стандартного механизма исключений (try/catch), как в Java или Python. Вместо этого используются явные ошибки (errors):

Пример стандартного подхода обработки ошибок в Go:

package main

import (
	"fmt"
	"os"
)

func readFile(filename string) ([]byte, error) {
	data, err := os.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return data, nil
}

func main() {
	data, err := readFile("file.txt")
	if err != nil {
		fmt.Println("Ошибка чтения файла:", err)
		return
	}
	fmt.Println("Данные файла:", string(data))
}

Это делает обработку ошибок явной, предсказуемой и безопасной.

🐹 Заключение

Go — простой и приятный язык, который открывает возможности для создания быстрых и надежных приложений. Он отлично подходит новичкам и опытным разработчикам, особенно если тебе важно писать быстрый и понятный код, легко поддерживать проекты и запускать приложения везде.

Попробуй Go — и ты быстро почувствуешь, как это удобно! 🚀🐹