Вебинары Разобраться в IT Реферальная программа
Программирование Аналитика Дизайн Маркетинг Управление проектами
27 Май 2024
14 мин
8090

Golang (Go): что это за язык программирования и стоит ли его учить

Рассказываем, что такое Golang (Go) и стоит ли его учить.

Go — это строго типизированный и компилируемый язык программирования, разработанный в 2007 году в компании Google. Анонсировали Go в 2009 году.

Главные преимущества Go:

  • скорость разработки, как в Python;
  • скорость работы, как в C/C++.

Go — популярный и простой язык программирования. Его используют в облачных технологиях, CLI-приложениях, веб-разработке, devOps и SRE.

Go имеет открытый исходный код и большое сообщество. Его используют в Google, Microsoft, Meta*, Uber, Netflix.

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

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

Для чего используется

Основное направление разработки на Go — веб-сервисы и утилиты. Согласно опросу jetbrains за 2021 год, 36% программистов используют Go для веб-приложений.

Направления разработки на Go

Несколько популярных утилит, которые написаны на Go:

  • Kubernetes — система управления контейнеризованными приложениями.
  • Docker — инструмент для контейнеризации приложений.
  • Prometheus — инструмент для сбора и обработки метрик.
  • GitHub CLI — консольное приложение от GitHub для более удобной работы с Git в командной строке.

Преимущества языка

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

Интерпретируемый язык

Программы на таком языке выполняются построчно с помощью вспомогательной программы — интерпретатора. Эта программа последовательно транслирует (интерпретирует) каждую строку исходного кода в машинный код и сразу же исполняет.

К таким языкам относятся: PHP, Python, JavaScript.

Компилируемый язык

Программы на таком языке необходимо предварительно транслировать (скомпилировать) в машинный код. Это занимает определенное время перед запуском, зато такие программы работают быстрее.

К таким языкам относятся: Go, C++, Haskell, Rust, Swift.

Динамически или статически типизируемые языки

Динамически типизируемым называется язык, тип переменной которого определяется в момент присваивания значения (в момент исполнения кода) и может меняться по мере исполнения программы. В статически типизируемом языке тип переменной определяется в момент компиляции — и в процессе исполнения не может измениться.

Динамически типизируемые языки: Python, PHP, JavaScript, Ruby.

Статически типизируемые языки: Go, Java, C++, Kotlin.

Go поддерживает многопоточность и имеет автоматический сборщик мусора. У Go отличная стандартная библиотека, которая предлагает базовую функциональность под большинство потребностей. А в версии 1.18 добавилась поддержка дженериков.

Простота Go — главный плюс для новичка или специалиста, который хочет сменить язык. У Go простой синтаксис, код легко читается.

Другие преимущества:

  • Наличие инструментов для тестирования, профилирования и форматирования кода.
  • Быстрая скорость компиляции. Даже для больших проектов компиляция занимает секунды.
  • Активное сообщество, много статей и конференций. Большое количество open-source библиотек.

Типы данных

Базовые типы данных:

  • Целочисленные типы — int8, int16, int32, int64 и uint8, uint16, uint32, uint64.
  • Числа с плавающей точкой — float32, float64.
  • Комплексные числа — complex64, complex128.
  • Булевый тип — bool.
  • Строки — string.

Еще в Go есть два встроенных типа, которые ссылаются на базовые (такое переопределение называется alias):

  • Byte типа uint8, одно из использований — строки. Строка в Go — это последовательность байтов.
  • Rune типа int32, используется для хранения одного unicode-символа (single unicode code point), например €.

Прочие типы:

// Массив фиксированной длины
[10]int64

// Слайс — массив динамической длины
[]int64

// Указатель на объект
*int64

// Мапа. Он же (тип) dictionary, словарь или ассоциативный массив
map[string]int64

// Канал. Используется для конкурентного чтения/записи
chan int64 // канал на запись и чтение
chan int64 // канал только на запись
chan int64 // канал только на чтение

// Структура. Последовательность элементов, имеющих название и тип
struct {
Title string
Author string
}

// Функция
func(int64) bool

// Интерфейс
interface {
Method1(int64)
Method2() (bool, error)
}

Параллелизм в Golang

Все процессы в Golang выполняются конкурентно в функциях, которые называются горутины. «Конкурентно» означает, что в один момент времени могут исполняться несколько процессов.

Не путать с параллельностью: при конкурентности исполнение двух и более процессов происходит поочередно, а при параллельном они исполняются одновременно и независимо друг от друга.

Go способен выполнять процессы и параллельно.

Горутины

Горутину можно описать как обычную функцию, вызванную с помощью префикса go. Горутины не блокируют выполнение основного метода, в котором они вызываются.

func calculateSomthing() {
// Делаем вычисления
// ...

// Вызываем функцию в горутине
go logInformation(data)

// При вызове метода logInformation исполнение основной функции не будет ждать его завершения, а продолжит свою работу
// Важно понимать, что выполнение метода calculateSomething может завершиться раньше, чем logInformation

//...
// Делаем оставшиеся вычисления
}

Каналы

Один из постулатов Go гласит:

Do not communicate by sharing memory; instead, share memory by communicating.

«Не общайтесь разделением памяти; разделяйте память через общение.»

Здесь говорится о том, что не нужно использовать общую память между горутинами, правильнее передавать данные напрямую. Под общей памятью можно представить объект с которым взаимодействуют несколько горутин.

Как раз для синхронизации данных между горутинами в Go используются каналы. Их можно представить в виде очереди FIFO (first in, first out): одна функция пишет данные, а другая читает.

chan int
c := make(chan int) // Создаем небуферизированный (без указания размера) канал
// Запустим сортировку list в горутине; после сортировки отправим в канал сигнал о завершении
go func() {
list.Sort()
c <- 1 // Отправляем сигнал; тип данных и значение в данном примере не важны
}()
doSomethingForAWhile()
<-c // Ждем, пока в канал поступит сообщение, для продолжения работы
//...

Каналы — одна из самых сложных тем в Go. Использовать их нужно с осторожностью и не во всех местах.

Одна из особенностей каналов — запись/чтение в небуферизированный канал блокируется.

Разберем пример выше, чтобы понять, как это работает. Когда мы вызываем горутину, в которой сортируем массив, программа продолжает выполняться. Это будет продолжаться, пока мы не дойдем до чтения из канала <-c. В этот момент программа перестанет выполняться, то есть заблокируется до тех пор, пока мы не прочитаем значение из канала. В свою очередь запись в канал c <- 1 в горутине будет заблокирована, пока кто-то не начнет читать из канала.

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

Синтаксис Go

У Go достаточно легкий синтаксис: программы, которые написаны на этом языке, легко читаются.

Пакеты

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

Например, пакет из стандартной библиотеки Go — rand. Он импортируется как math/rand и находится в поддиректории пакета math.

Как выглядит пакет в коде:

package main // Название пакета.

func main() {
//...
}

Импорт

Пакеты в Go импортируются с помощью ключевого слова import и полного имени пакета. Дальнейшее использование пакета будет выглядеть так: имя_пакета.метод()
package main // Название пакета.

import (
"fmt" // Импортируем пакет fmt.
myErr "errors" // Импортируем пакет errors, используя alias
)

func main() {
// Используем импортированный пакет fmt.
fmt.Println("Hello World")

err := myErr.New("error description")// обращаемся к пакету errors через указанный нами alias
}

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

package one

import "two" // Импортируем пакет two

// ... //

package two

import "one" // Импортируем пакет one. Получим ошибку при компиляции — import cycle not allowed

Функции

Одно из отличий Go — функции и методы могут возвращать несколько значений. Чаще всего можно встретить возврат ошибки последним значением и проверку err != nil сразу после вызова функции.

// Функция, возвращающая несколько параметров
func DoSomething() (int64, error)

В Go есть ключевое слово defer, которое позволяет отложить выполнение метода до выхода их функции.

func main() {
defer fmt.Println("world")

fmt.Println("Hello ")
}
// Вывод будет: Hello world

В данном примере сначала выполнится fmt.Println(«Hello «), а потом, в момент завершения функции main, выполнится fmt.Println(«world»).

Канонический пример использования defer — закрытие файла:

func Contents(filename string) (string, error) {
f, err := os.Open(filename)
if err != nil {
return "", err
}
defer f.Close() // f.Close() вызовется в момент выхода из функции Contents

// Работаем с файлом
}

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

Переменные

Создание переменной в Golang происходит несколькими способами:

var s1 string // Создаем переменную с нулевым значением; для строк - ""
s2 := "Hello Gophers"// С помощью оператора ":=" создаем и сразу инициализирует переменную s2
const s3 = "constant value" // Переменная константа. Ее значение нельзя изменить.

Операторы цикла

В Go есть несколько операторов цикла.

Цикл for с одним условием:

for a &amp;lt; b {
a *= 2
}

Классический for с инициализацией, условием и выражением:

for i := 0; i &amp;lt; 10; i++ { 
f(i) 
}

Цикл for с ключевым словом range. Работает c массивами, слайсами, строками, мапой и каналами.

var a [10]string
for i, s := range a {
// Тип i - int
// Тип s - string
// s == a[i]
g(i, s)
}

Ниже в таблице — описание аргументов итераций и их типы при использовании цикла с ключевым словом range:

Тип итерируемого объекта 1-е значение 2-е значение (может отсутствовать, необязательно использовать)
array, slice типа T индекс, i — int значение массива (слайса) по индексу i типа T
string индекс, i — int один символ unicode, начинающийся по индексу i, типа rune
map[K]T ключ типа K, key значение по ключу key типа T
channel типа T значение типа T

Условные конструкции

Конструкция if — else:

a := 1 b := 2 if a > b {
fmt.Println("a>")
} else { // else может отсутствовать
fmt.Println("a&lt;b")
}

Конструкция switch — case. Выполняется только одно из условий внутри switch.

a := 4
switch a {
case 4:
fmt.Println("a = 4")
default:
fmt.Println("a != 4")
}

// Может использоваться без выражения после switch
switch {
case x &lt; y: f1()
case x &lt; z: f2()
case x == 4: f3()
}

Массивы

Массивы в Go — это нумерованная последовательность элементов одного типа. Длина массива задается при объявлении переменной или инициализации. Ее нельзя менять.

var array [10]int
array2 := [3]int{1,2,3}
fmt.Println(len(array), len(array2)) // 10 3

Как массивы ведут себя в Go:

  • Присваивание копирует массив.
  • Функция, которая принимает в параметре массив, получит его копию, а не ссылку на массив.
  • Длина массива — часть типа. [5]int и [4]int — разные типы.

Срезы (слайсы)

Слайс в Go — более общая, мощная и удобная «обертка» над массивами. Большинство операций с массивами в Go происходит именно со слайсами.

var s1 []int // Определяем переменную типа слайс int; нулевое значение — nil.
s2 := []int{} // Инициализируем пустой слайс.
s3 := make([]int, 0, 10) // Выделяем память и инициализируем слайс на 10 элементов int.

s3 = append(s3, 1) // Добавляем элемент в слайс s3 функцией append.

Что важно знать про слайсы

В отличие от массивов размер слайса может изменяться. Так выглядит реализация данного типа «под капотом»:

type slice struct {
array unsafe.Pointer // Ссылка на исходный массив
len int // Текущая длина
cap int // Вместительность исходного массива
}

Слайс — структура со ссылкой на исходный массив и двумя параметрами: длина (len) и вместительность (cap). При присваивании или передаче в функцию слайс не копируется. Копируется только структура, которая его определяет. Ссылка на исходный массив остается прежней.

Поэтому, когда элемент добавляется в слайс функцией append, то результат присваивается обратно в переменную.

slice := []int{1,2,3}
slice = append(slice, 4)
fmt.Println(slice)// [1,2,3,4]

Это объясняется тем, что в момент добавления элемента в слайс, в исходном массиве может отсутствовать для него место. Для этого будет выделена память под новый массив большего размера.

Структуры

Структура — это последовательность элементов, которые называют полями. Каждое поле имеет уникальное название и тип в рамках одной структуры.

Все поля и методы, которые начинаются со строчной буквы, не экспортируются и будут недоступны во внешнем пакете. Поля и методы, которые начинаются с заглавной буквы, экспортируются.

// Пустая структура
struct {}

// Структура с пятью полями
struct {
x, y int
u float32
A *[]int
F func()
}

Востребованность языка

По результатам опроса Stack Overflow в 2022 году, Go находится на 9-м месте в топе самых оплачиваемых языков и на 13-м месте — среди самых популярных технологий.

Насколько нужен Golang разработчикам

В России много крупных компаний, которые пишут на Go: Ozon, МТС, «Сбер», «Совкомбанк», «Тинькофф», «Авито», «ВКонтакте», 2GIS, «Рамблер», «Магнит», «Лаборатория Касперского» и другие.

Обзор вакансий

На момент написания статьи доступно 124 вакансии на хабре и 3800 вакансий на хедхантере по запросу «Go»: от разработки веб-сервисов и бэкенда для игр до банковских продуктов и криптовалюты.

Компании всё чаще нанимают стажеров. С базовыми знаниями и отсутствием опыта можно устроиться на работу, быстро учиться на реальных проектах. А если успешно пройти испытательный срок, который обычно длится до полугода, можно стать младшим разработчиком.

На момент написания статьи вакансии для стажеров есть в компаниях Ozon, «Яндекс», «Авито», Wildberries и других.

По результатам опроса Stack Overflow за 2022 год, Go-разработчики получают за год в среднем $89 000 — на $14 000 больше, чем в прошлом году.

Вилка зарплат на российском рынке (статистика хедхантера и Хабр Карьеры):

  • младший специалист — 50 000 ₽;
  • специалист — 150 000 ₽ — 300 000 ₽;
  • старший специалист и выше — 250 000 ₽ — 450 000 ₽ и больше, иногда можно встретить
  • зарплату до $10 000.

Зарплата зависит от опыта, а не от требований компании.

Что можно написать на Go

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

Что еще пишут на Go:

  • Базы данных — Cockroach DB.
  • Системы управления контейнеризованными приложениями — Kubernetes, Minikube.
  • Системы контроля версий (GitHub, Gitlab, BitBucket и т. д.) — Gitea.
  • Системы хранения файлов (Amazon S3, Yandex Object Storage и т. д.) — Minio.
  • Key-value-базы данных (Redis, Memcached и т. д.) — etcd.
  • Системы синхронизации данных — Syncthing.
  • Игровые движки — Ebitengine.

На официальном сайте Go можно посмотреть, как язык используют крупные компании.

Как установить и начать использовать

Посмотреть на синтаксис и попробовать кодить можно в «песочнице» на официальном сайте.

Скачать тоже можно с официального сайта.

После того как установите, в консоли введите команду go version, чтобы убедиться, что всё прошло успешно:

╰─❯ go version
go version go1.19 darwin/arm64

В любой директории создаем файл с именем main.go. Название может быть любое, но пакет — main: запустить код можно только из него.

package main

import "fmt"

func main() {
fmt.Println("Hello Gopher!")
}

Запускаем программу с помощью команды go run имя_файла.go:

╰─❯ go run main.go
Hello Gopher!

Profit!

Подборка обучающих материалов

Когда изучаете любой язык, больше практикуйтесь. Это нужно, чтобы закрепить пройденный материал.

Если нет идей для проекта, можно использовать гитхаб. Найти проект, разобраться в нём, понять, что он делает, и реализовать самостоятельно.

Если знаете английский язык — лучше начать с материалов на официальном сайте:

  • Go tour — интерактивный вводный курс.
  • Effective Go — поможет понять, как правильно писать чистый и идиоматический код на Go.
  • Documentation — документация Go, там можно найти туториалы и полезные статьи.
  • 101go — бесплатная книга про Go, доступная онлайн и в форматах epub, azw3, mobi, pdf.
  • Go in Action.
  • Introducing Go.
  • Mastering Go — есть на русском языке.
  • Блог Dave Cheney — много полезной информации про Go, лучшие практики, разборы сложных тем. Есть мастер-класс про производительность в Go.
  • Подкаст Go Time.
  • r/golang — сообщество Go на Reddit: можно задать вопросы, участвовать в обсуждениях. Каждый месяц выкладывают закрепленный пост с актуальными вакансиями.

Конференции на английском:

Что есть на русском:

  • «Маленькая книга о Go» — знакомство с языком.
  • «Golang для профи»(Mastering Go) — не только база Go, но и нюансы использования. Есть информация про компилятор, работу сборщика мусора, реализацию hashmap. Глава про машинное обучение, использование Go с Docker и Kubernetes и другое.
  • Про Go на хабре.


Конференции:

Итоги

  • Golang — относительно молодой, но популярный язык.
  • У Go легкий синтаксис, на него несложно перейти с другого языка. Хорошо подойдет новичкам.
  • Вместе с Go поставляется набор необходимых утилит для тестирования, форматирования и профилирования кода.
  • Много вакансий, есть из чего выбирать.
  • Высокие зарплаты
Проверь как ты усвоил материалы статьи
Пройди тест и узнай насколько ты лучше других читателей

Добавить комментарий