Go
Вольный и расширенный перевод оригинального репозитория Go Cheat Sheet на русский язык.
Другие ресурсы
Подборка полезных и бесплатных ресурсов для изучения Go на русском языке:
- Эффективный Go - перевод официальной документации Effective Go (не завершен и устарел).
- Эффективный Go - перевод от сентября 2024 года.
- Go в примерах - исходный код для сборки статического сайта Go в примерах (форк gobyexample).
- Введение в программирование на Go (веб-версия) - перевод книги An Introduction to Programming in Go.
- Маленькая книга о Go - перевод The Little Go Book.
- Паттерны параллельного программирования Go.
- Курс по изучению Golang для начинающих.
- Обучение программированию на языке Go в тренажере (онлайн компилятор).
- Руководство по языку Go от Metanit.
- Шпаргалка по Go в переводе с Немецкого языка.
- Гайды Uber по написанию кода на Go - русский перевод оригинального репозитория.
- GUI на Golang на GTK+ 3.
Бесплатные курсы от Stepik с получением сертификата:
- Go - первое знакомство - 42 урока, 110 тестов, 45 задач (20к учащихся, рейтинг: 4.9).
- PRO Go. Основы программирования - 38 урока, 121 тестов, 191 задач (13к учащихся, рейтинг: 4.8).
- Программирование на Golang - 35 урока, 64 тестов, 94 задач (65к учащихся, рейтинг: 4.7).
Другие бесплатные курсы:
- Разработка веб-сервисов на Golang - курс по Go от Mail Ru на платформе Coursera.
- Основы Go - курс от Яндекс Практикум (2 модуля на 30 часов).
- Основы Go - курс от Хек Слет (34 урока, 97 тестов и 37 упражнений в тренажере).
Участники
Если вы нашли ошибку или хотите расширить список шпаргалок, а также знаете другие источники для изучения, сообщите о них, внеся изменения через Pull Requests.
Источники
Большинство примеров кода взяты из официального тура по Go, который является прекрасным введением для знакомства с языком.
Вы также можете использовать онлайн компилятор на официальном сайте для запуска и проверки блоков кода.
Описание языка
- Императивный язык, где описывается последовательность шагов (инструкций), которые необходимо выполнить для достижения результата. В отличии от декларативных языков, где описывается результат, который нужно получить, оставляя процесс выполнения скрытым (например, как в
SQL
илиHTML
). - Используется статическая типизация для проверка типов переменных во время компиляции. Это когда тип переменной не может быть изменен после его присвоения (например, как в
TypeScript
в отличии отJavaScript
). - Синтаксис похож на
C
(но меньше скобок и нет точек с запятой в конце каждой строки), а структура — наOberon-2
. - Компилируется в машинный код без использования промежуточных слоев (
Runtime
, например, какJVM
вJava
или.NET
вC#
), который должен быть установлен на машине для работы программы. - Нет классов, но есть структуры с методами.
- Не предоставляет подклассов, основанного на типах, но имеет возможность заимствовать части реализации, встраивая типы в структуру или интерфейс (embedding).
- Функции могут возвращать несколько значений и их можно присваивать переменным, так как они рассматриваются как объекты.
- Функции можно передавать в другие функции в качестве аргументов, а также функции могут возвращать другие функции как результат.
- Имеет замыкания (
closures
), которые позволяют функциям хранит и использовать переменные из внешней области видимости, даже если она выполняется в другом контексте (например, за пределами этой области). - Невозможно напрямую изменять значение указателя с помощью арифметических операций (например,
ptr++
). Это нужно, что бы исключить возможные ошибки, такие как выход за пределы памяти или доступ к неправильным участкам памяти. - Встроенные примитивы параллелизма: горутины и каналы.
- Поддерживаются динамические и статические срезы (
slices
, аналог списков или массивов в других языках, где элементы хранятся в порядке их добавления и индексируются числами), а также карты (maps
, аналог словарей или хэш-таблиц, где содержится уникальный ключ и его значение).
Базовый синтаксис
Привет мир
Файл hello.go
:
package main
import "fmt"
func main()
Запуск:
go run hello.go
Выведет на экран Hello Go
Операторы
Арифметика
Оператор | Описание |
---|---|
+ | сложение |
- | вычитание |
* | умножение |
/ | деление * |
% | остаток |
& | побитовое и |
| | побитовое или |
^ | побитовое исключающее или * * |
&^ | очистить бит (и нет ) * * * |
<< | сдвиг влево * * * * |
>> | сдвиг вправо |
* Если оба операнда имеют целый тип (int
, int8
, int32
, int64
), результат также будет целым числом, при этом остаток отбрасывается. Если хотя бы один из операндов имеет тип с плавающей точкой (float32
, float64
), результат будет дробным числом.
* * Возвращает 0
, если биты двух операндов равны, или 1
, если биты двух операндов различны.
* * * Возвращает 0
, если соответствующий бит второго операнда равен 1
, или бит первого операнда (0
или 1
), если соответствующий бит второго операнда равен 0
.
* * * * Сдвигает все биты числа влево на указанное количество позиций (аналог умножения числа на 2
в степени количества сдвигов), а новые биты справа заполняются нулями.
Сравнение
Оператор | Описание |
---|---|
== | равно |
!= | не равно |
< | меньше |
<= | меньше или равно |
> | больше |
>= | больше или равно |
Логика
Оператор | Описание |
---|---|
&& | логическое и |
|| | логическое или |
! | логическое отрецание |
Другие
Оператор | Описание |
---|---|
& | адрес / создать указатель |
* | разыменовать указатель |
<- | оператор отправки / получения |
Декларации
Тип указывается после идентификатора (названия переменной):
var foo int // объявление без инициализации значения
var foo int = 42 // объявление с инициализацией
var foo, bar int = 42, 1302 // объявить и инициализировать несколько переменных одновременно
var foo = 42 // тип пропущен, будет выведен
foo := 42 // сокращение при объявление переменной (ключевое слово var опущено, тип данных определяется автоматически)
const constant = "Это константа, которая используется для хранения неизменяемых данных"
// iota можно использовать для увеличения числа, начиная с 0
const (
_ = iota
a
b
c = 1 << iota
d
)
fmt.Println(a, b) // 1 2 (0 - пропускается)
fmt.Println(c, d) // 8 16 (2^3, 2^4)
Функции
// Простая функция
func functionName()
// Функция с параметрами (тип идет после идентификаторов)
func functionName(param1 string, param2 int)
// Несколько параметров одного типа
func functionName(param1, param2 int)
// Объявление типа для возвращаемого значения (идет после скобок параметров или во вторых скобках, если значений несколько)
func functionName() int
// Может возвращать несколько значений одновременно
func returnMulti() (int, string)
var x, str = returnMulti()
// Возвращаем несколько именованных результатов
func returnMulti2() (n int, s string)
var x, str = returnMulti2()
func main()
Замыкания
// Дочерние функции могут получить доступ к переменным, объявленным в родительской функции
func scope() func() int
func another_scope() func() int
func outer() (func() int, int)
Вариативные функции
Вариативная функция работает и вызывается как любая другая функция, за исключением того, что в нее возможно передать произвольное количество аргументов, используя ...
перед типом данных указанного параметра.
func main()
func adder(args ...int) int
Типы данных
bool // логический тип (принимает true или false)
string // строка (текст)
int int8 int16 int32 int64 // целое число
uint uint8 uint16 uint32 uint64 uintptr // беззнаковый целочисленный тип размером
byte // псевдоним для uint8
rune // псевдоним для int32 ~= символ (кодовая точка Unicode)
float32 float64 // число с плавающей точкой одинарной и двойной точности
complex64 complex128 // комплексное число (1 + 2i или 3.14 + 4.2i), имеющие реальную и мнимую часть
interfae // универсальный тип, который может позволяет работать с переменными неизвестного или изменяющегося типа
Все предварительно объявленные идентификаторы Go
определены в пакете builtin.
Преобразование типов
var i int = 42
var f float64 = float64(i) // преобразуем тип данных int в float64
var u uint = uint(f) // преобразуем тип данных float64 в unit
// Альтернативный синтаксис
i := 42
f := float64(i)
u := uint(f)
Структуры управления
Условия if
func main()
Условия switch
После выполнения условия при использование переключателей, прерывания обрабатываются автоматически.
package main
import (
"fmt"
"os"
)
func main()
// Как в случае с "for" и "if", возможно иметь оператор присваивания перед значением switch
switch os := runtime.GOOS; os
// Возможно использовать сравнения
number := 42
switch
// Все случаи могут быть представлены в виде списков, разделенных запятыми
var char byte = '?'
switch char
Циклы
В Go
используются только универсальные циклы for
, другие операторы (например, while
или until
) отсутствуют.
// Используется 9 интераций с 1 по 9 (до 10)
for i := 1; i < 10; i++
// Цикл (loop) - while
for ; i < 10;
// Если есть только условие, точки с запятой опускаются
for i < 10
// Если опустить условие, равноценно использованию while (true)
for
// Использование пропуска и прерывания в цикле
// Метка here (произвольное имя) позволяет указать целевой цикл, на который будут ссылаться операторы continue и break
here:
// Используем 2 интерации в внешнем цикле (от 0 до 1)
for i := 0; i < 2; i++
// 1-я интерация: внешний цикл с значением i=0 в внутреннем цикле пропускает интерацию внешнего цикла, т.к. срабатывает условие i==0
// 2-я интерация: внешний цикл с значением i=1 в внутреннем цикле пропускает условие i==0
// Переменная j получает значение 2, которое печатается и завершает внутренний (текущий) цикл во втором условие
// Программа завершается, т.к. интерации внешнего цикла закончились
there:
for i := 0; i < 2; i++
Примеры циклов
package main
import "fmt"
// Функция, возвращающая название месяца через условную конструкцию switch
func getMonthName(month int) string
// Второй вариант функции через классическое условие по индеку массива
func getMonthName2(month int) string
func main()
Типы последовательностей
Массивы, срезы и диапазоны представляют собой структуры данных, хранящие упорядоченные наборы значений.
Статические срезы (массивы)
Статические срезы подразумеваются как массивы.
var a [10]int // объявить массив int длиной 10 (длина массива является частью типа)
a[3] = 42 // присвоить значение элементу, по его порядковому номеру
i := a[3] // прочитать элементы
// Возможные варианты объявление с инициализацией значений
var a = [2]int
// Массив из двух элементов: [1 2]
a := [2]int
// Многоточие используется компилятором для вычисления длины массива
a := [...]int
Динамические срезы
Динамический срез объявляется аналогично статическому, но длина не указывается.
var a []int // объявить срез
var a = []int // объявить и инициализировать срез
a := []int // [1 2 3 4]
chars := []string // [a b c]
var b = a[lo:hi] // создать срез от индекса lo до hi-1
var b = a[1:4] // срез c индекса 1 по 3 (до 4)
var b = a[:3] // отсутствие первого индекса подразумевает 0
var b = a[3:] // отсутствие последнего индекса подразумевает len(a) (т.е. последний идекс по длинне индекса)
a = append(a,17,3) // добавление элементов к срезу a с помощью функции append
c := append(a,b...) // объединение срезов a и b
a = make([]byte, 5, 5) // первый аргумент длина, второй емкость
a = make([]byte, 5) // емкость необязательна
x := [3]string // создаем массив
s := x[:] // создать срез из массива
Операции с срезами
len(a)
возвращает длину среза/массива. Это встроенная функция, а не метод массива.
// Цикл по массиву/срезу
for i, e := range a
// Если нужен только элемент "e"
for _, e := range a
// Если нужен только индекс
for i := range a
Карты
package main
import "fmt"
type Vertex struct
func main()
Примеры срезов и карт
package main
import "fmt"
func main()
Структуры
Вместо классов (class
) в Go
используются структуры (тип данных struct
), которые могут иметь методы. Поля структуры всегда инициализируются нулевыми значениями при её объявлении.
// Объявление структуры с названием Vertex с помощью ключевого слова "type"
type Vertex struct
// Создание структуры
var v = Vertex // инициализация данных в структуре
var v = []Vertex // инициализация среза в структуре
var v = Vertex // создание структуры с опредилением значений с помощью ключей
v.X = 4 // доступ к значениям
// Объявление метода (принимающий тип), находится между ключевым словом func и именем метода
// Структура копируется при каждом вызове метода
func () float64
// Вызов метода
v.Abs()
// Для мутирующих методов необходимо использовать указатель (см. ниже) на Struct в качестве типа
// При этом значение структуры не копируется для вызова метода
func (n float64)
Анонимные структуры
Безопаснее и дешевле, чем использование map[string]interface{}
.
point := struct
Указатели
p := Vertex // "p" это структура Vertex
q := &p // "q" указывает на структуру Vertex
r := &Vertex // "r" также указывает на структуру Vertex
// Объявление переменной с указателем на структуру *Vertex
var s *Vertex = new(Vertex) // функция "new" создает указатель на новый экземпляр структуры
Интерфейсы
Интерфейс - это набор методов (требований), которые должен иметь тип, чтобы соответствовать этому интерфейсу.
// Объявление интерфейса с одинм методом Awesomize(), который возвращает строку
type Awesomizer interface
// Обычная структура, которая может реализовывать методы
type Foo struct
// Добавление (реализация) метода Awesomize() в структуре Foo
// Тип автоматически соответствует интерфейсу, если он реализует все его методы
func () string
Встраивание
В Go
нет подклассов, вместо этого используется встраивание интерфейса и структуры, которое добавляет методы встроенной структуры к внешней.
// В структуру Server встраиваются все методы, которые есть у метода Logger из структуры log
type Server struct
// Структура Server инициализируется с помощью указателя на log.Logger
server := &Server
// Когда вызывается server.Log(...), Go автоматически перенаправляет вызов к server.Logger.Log(...).
server.Log(...)
// Поле встроенного типа доступно через его имя, по этому переменной можно присвоить ссылку на server.Logger
var logger *log.Logger = server.Logger
Обработка ошибок
Обработка исключений отсутствует. Вместо этого функции, которые могут выдать ошибку, просто объявляют дополнительное возвращаемое значение типа error (чаще всего вторым возвращаемым параметром).
Встроенный тип интерфейса error
— это общепринятый интерфейс для представления состояния ошибки, при этом нулевое значение не представляет ошибки.
type error interface
Пример:
package main
import (
"errors"
"fmt"
"math"
)
// Определение функции sqrt должно быть вне main
func sqrt(x float64) (float64, error)
func main()
Параллелизм
Горутины
Горутины — это легковесные потоки (управляемые Go
, а не потоками ОС).
go f(a, b)
запускает новую горутину, которая запускает f
(при условии, что f
— это функция).
// Просто функция (которая позже может быть запущена в горутине)
func doStuff(s string)
func main()
Синхронизация
Пакет sync
используется для ожидания завершения всех запущенных горутин.
package main
import (
"fmt"
"sync"
)
func doStuff(s string, wg *sync.WaitGroup)
func main()
Таймер
Таймеры из пакета time
используются для задержки (паузы) на указанное время:
package main
import (
"fmt"
"time"
)
func goRun()
func main()
Небуферизованный канал
Небуферизованный канал блокирует операцию записи, пока не будет выполнено чтение, и наоборот.
// Создаем небуферизованный канал типа "int"
ch := make(chan int)
// Отправляем значение 42 в канал "ch"
// Операция блокирует текущую горутину, пока другая горутина не прочитает его значение
ch <- 42
// Получаем значение из канала "ch"
// Это также блокирует выполнение, пока не будет доступно значение для чтения в канале
v := <-ch
Буферизованный канал
Буферизованный канал позволяет отправлять и получать данные без блокировки, пока размер буфера не будет превышен, как только буфер заполняется, запись блокируется, пока другие горутины не начнут извлекать значения из канала.
Закрытие канала — это сигнал получателю, что больше значений не будет отправляться в канал, при этом отправленные в него данные не удаляются. Это необходимо для того, чтобы получатели знали, что можно завершить чтение. Закрытие канала происходило только в той горутине, которая отправляет данные.
package main
import "fmt"
func main()
Вывод: 0 1 2 3 4 5 6 7 8 9 Канал закрыт, данные не доступны
Селекторы
Оператор select
работает как многоканальный оператор switch
. Выбор блоков в операциях с несколькими каналами, если один из них разблокируется, выполняется соответствующие условие. Он блокируется до тех пор, пока одно из выражений case
не будет готов к выполнению, при этом остальные игнорируются.
package main
import (
"fmt"
"time"
)
func doStuff(channelOut, channelIn chan int)
func main()
Аксиомы канала
Отправка в пустой канал блокируется навсегда и вызывает фатальную ошибку:
var c chan string
c <- "Hello, World!"
Чтение из нулевого канала блокируется навсегда:
var c chan string
fmt.Println(<-c)
Отправка в закрытый канал вызывает панику:
var c = make(chan string, 1)
c <- "Hello, World!"
close(c)
c <- "Hello, Panic!"
Прием из закрытого канала немедленно возвращает нулевое значение:
var c = make(chan int, 2)
c <- 1
c <- 2
close(c)
for i := 0; i < 3; i++
// 1 2 0
Примеры каналов и горутин
package main
import (
"fmt"
"time"
"sync"
)
func goRun(ch chan string)
func goRunThree(ch chan string)
func printMessage(msg string, wg *sync.WaitGroup)
func main()
Вывод
package main
import "fmt"
func main()
Переключение типа
Переключение типа похоже на обычный оператор switch
, но в условиях указывается типы (а не на значения), которые сравниваются с типом значения, содержащегося в данном значении интерфейса.
package main
import "fmt"
func do(i interface)
func main()
// Число 21 равно 42 по типу данных
// Значение "hello" равно 5 bytes
// Тип bool неизвестен
Встроенные пакеты
- Декларация пакета (объявление через
import
) производится в начале каждого исходного файла. - Исполняемые файлы находятся в пакете
main
. - Имя пакета соответствует последнему имени в пути импорта (например,
math/rand
- пакетrand
). - Идентификатор функции в верхнем регистре является экспортируемый (доступны из других пакетов).
- Идентификатор функции в нижнем регистре является частный (недоступны из других пакетов).
Встраивание файлов
Программы Go
могут встраивать статические файлы с помощью пакета embed
и директиву go:embed path/filename
:
package main
import (
"embed"
"fmt"
"io"
"log"
"net/http"
)
var content embed.FS
func main()
// Имитация реальных файлов с их содержимым для запуска в Playground
-- static/a.txt --
hello a
-- static/b.txt --
hello b
HTTP сервер
Реализация простого API
сервера на базе встроенной библиотеки net/http
:
package main
import (
"encoding/json"
"fmt"
"net/http"
)
// Обработчик API
func apiHandler(w http.ResponseWriter, r *http.Request)
func main()
Делаем запрос к API
через curl
:
| | |
HTTP клиент
Делаем запрос к API
в Go
:
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main()
HTTP
запрос к API
для получения последней версии релиза указаного репозитория в GitHub:
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
)
// Формируем структуру ответа от API
type GitHubRelease struct
func main()
go run main.go
Вызов системных команд
Проверка доступности всех хостов в указанной подсети (асинхронный ICMP
опрос):
package main
import (
"fmt"
"os"
"os/exec"
"strings"
"sync"
)
func pingHost(ip string, wg *sync.WaitGroup)
func main()
go run main.go 192.168.3.0
Математические вычисления
package main
import (
"fmt"
"math"
)
func customCeil(numerator int, denominator int) int
func main()
Регулярные выражения
Элементы синтаксиса
Основные элементы синтаксиса регулярных выражений:
Символ | Описание |
---|---|
. | любой символ, кроме символа новой строки |
* | 0 или более повторений |
+ | 1 или более повторений |
{n} | точно n повторений (например, a{3} , соответствует: "aaa" ) |
{n,} | минимум n повторений (например, a{2,} , соответствует: "aa" , "aaa" и т.д.) |
{n,m} | от n до m повторений (например, a{2,4} , соответствует: "aa" , "aaa" , "aaaa" ) |
? | 0 или 1 повторений |
^ | начало строки |
$ | конец строки |
[] | группа символов (например, [a-z] ) |
\s | любой пробельный символ (пробел, табуляция, новая строка и другие пробельные символы) |
\d | цифра (эквивалентно [0-9] ) |
\D | любой символ, не являющийся цифрой (эквивалентно [^0-9] ) |
\w | буквенно-цифровой символ (буквы, цифры и подчеркивание, эквивалентно [a-zA-Z0-9_] ) |
\W | не буквенно-цифровой символ (эквивалентно [^a-zA-Z0-9_] ) |
\b | граница слова (например, \bword\b соответствует "word" , и не подхоит "wordy" ) |
(?i) | делает выражение нечувствительным к регистру |
\ | экранирование специальных символов |
() | группа захвата |
| | логическое ИЛИ (например, `a |
Функции regexp
Основные функции пакета regexp
:
regexp.MatchString
— проверяет, соответствует ли строка регулярному выражению.
package main
import (
"fmt"
"regexp"
)
func main()
regexp.Compile
— компилирует регулярное выражение и возвращает объект типа*regexp.Regexp
, если выражение корректное, или возвращается ошибка.
package main
import (
"fmt"
"regexp"
)
func main()
regexp.FindAllString
— находит все подстроки в строке, которые соответствуют регулярному выражению, и возвращает их в виде среза строк.
package main
import (
"fmt"
"regexp"
)
func main()
regexp.ReplaceAllString
— заменяет все соответствующие части строки.
package main
import (
"fmt"
"regexp"
)
func main()
- Группы захвата
package main
import (
"fmt"
"regexp"
)
func main()
- Извлечение логина и домена из почтовых адресов
package main
import (
"fmt"
"regexp"
)
func main()
Copy Codehttps://lifailon.github.io/search_index.en.json$MATCHES more matches