План
- Синтаксис и структура: ознакомьтесь с базовыми элементами языка Go, такими как переменные, типы данных, операторы, условные выражения и циклы.
- Функции: изучите создание и использование функций в Go, а также передачу параметров по значению и по ссылке.
- Срезы (slices) и массивы: узнайте, как создавать, использовать и манипулировать срезами и массивами в Go.
- Структуры и методы: ознакомьтесь с определением структур и созданием методов, которые работают с ними.
- Указатели: изучите работу с указателями в Go и их применение для изменения значений переменных и передачи данных.
- Интерфейсы: узнайте, как создавать интерфейсы и реализовывать их в Go для достижения полиморфизма.
- Горутины и каналы: изучите концепцию параллельного и конкурентного программирования с помощью горутин и каналов в Go.
- Обработка ошибок: ознакомьтесь с практиками обработки ошибок в Go, используя механизмы возврата ошибок и паники.
- Пакеты и импорты: изучите организацию кода в пакеты и импортирование пакетов в Go.
- Тестирование: узнайте, как создавать модульные тесты для своего кода с помощью пакета
testing
в Go. - Работа с файлами и сетью: ознакомьтесь с базовыми операциями работы с файлами и сетью в Go.
- Развертывание приложений: изучите процесс сборки и развертывания приложений на языке Go, включая управление зависимостями и компиляцию.
Синтаксис и структура
Настраиваем Goland
Указываем пути до папки с исходными кодами приложений
И до папки с компилятором Go
Первое приложение. main функция
Первым делом в корневом файле всегда обязательно должен присутствовать пакет main
и функция main
, которые будут хранить основные пакеты приложения и функцию запуска приложения на Go
В myVar
записана переменная, а уже через библиотеку форматирования fmt
и её метод Print
можно вывести значение в консоли
- Первой командой устанавливается корневой путь до SDK Go (компилятор)
- Второй - GOPATH - это переменная среды, используемая в Go для указания корневого каталога рабочего пространства, где хранятся исходные коды и бинарные файлы проектов на Go.
- Третья команда вызывает компилятор Go через
build
и ключом-o
задаётся путь выходного файла. Путь будет иметьtmp
директорию. Последний аргумент - это целевой файл, который нужно скомпилировать.
Так же мы можем запустить нужный файл через данную команду:
Так же мы можем сбилдить нужный нам файл в бинарник нашей системы
Переменные и типы данных
В Go, как и в других языках, присутствуют самые распространённые типы данных:
bool
: логический тип данных, который может бытьtrue
илиfalse
.- числовые типы данных:
int
(int8
,int16
,int32
,int64
): целое число со знаком.uint
(uint8
,uint16
,uint32
,uint64
): целое число без знака.float32
,float64
: числа с плавающей точкой.complex64
/complex128
byte
=uint8
rune
=int32
string
: строки текста.- массивы и срезы: коллекции элементов определенного типа.
struct
: пользовательские типы данных, состоящие из полей разных типов.- указатели: хранят адрес памяти другой переменной.
interface
: набор методов, объединенных под общим интерфейсом.func
: фрагменты кода, которые можно вызывать и использовать.maps
: коллекции пар ключ-значение.channels
: используются для обмена данными между горутинами.
Мы можем указать переменную через три конструкции:
var имя тип_данных = значение
- сами указываем переменную и тип данныхvar имя = значение
- сами указываем переменную без типа данныхимя := значение
- автоматическое указание типа данных
Golang почти строготипизированный язык, поэтому если мы не укажем тип, но укажем определённую переменную, то поменять строку на чичсло - не получится
Так же у нас есть явный перевод данных и с помощью того же int
можно перевести число одного типа в другое
Так же можно указать сразу несколько переменных подобным синтаксисом:
Или подобным:
Работа со строками
Чтобы объединять строки, мы можем использовать просто оператор +
Так же мы можем конструировать строки через использование метода Sprintf
, куда первым параметром передаём строку и указатели (%s
- строка, %d
- число), а дальше переменные с нужными типами данных
Через функцию Join
мы можем объединить массив в строку
Функция Split
позволит разбить строку по определённому разделителю в массив
strings.Contains(s, substr)
:- Проверяет, содержит ли строка
s
подстрокуsubstr
. - Возвращает булево значение
true
, еслиs
содержитsubstr
, иначеfalse
.
- Проверяет, содержит ли строка
strings.HasPrefix(s, prefix)
:- Проверяет, начинается ли строка
s
с префиксаprefix
. - Возвращает булево значение
true
, еслиs
начинается сprefix
, иначеfalse
.
- Проверяет, начинается ли строка
strings.HasSuffix(s, suffix)
:- Проверяет, заканчивается ли строка
s
суффиксомsuffix
. - Возвращает булево значение
true
, еслиs
заканчивается наsuffix
, иначеfalse
.
- Проверяет, заканчивается ли строка
strings.Replace(s, old, new, n)
:- Заменяет все вхождения подстроки
old
в строкеs
на подстрокуnew
. - Можно указать необязательный аргумент
n
, чтобы ограничить количество замен. - Возвращает новую строку, полученную после замены.
- Заменяет все вхождения подстроки
strings.ToLower(s)
:- Преобразует все символы строки
s
в нижний регистр. - Возвращает новую строку с преобразованными символами.
- Преобразует все символы строки
strings.ToUpper(s)
:- Преобразует все символы строки
s
в верхний регистр. - Возвращает новую строку с преобразованными символами.
- Преобразует все символы строки
strings.TrimSpace(s)
:- Удаляет все начальные и конечные пробелы из строки
s
. - Возвращает новую строку без пробелов в начале и конце.
- Удаляет все начальные и конечные пробелы из строки
Циклы
Цикл for
Основной цикл, который существует в Go представлен следующими вариациями:
Цикл range
Цикл range
используется для итерации по элементам массива, среза (slice), строки, карты (map) или канала (channel). Он возвращает индекс или ключ текущего элемента и его значение
while
Цикл while моделируется обычным оставлением одного кондишенела в цикле перебора
do-while
В Go также нет прямой поддержки цикла do-while
, но можно смоделировать его, используя бесконечный цикл и прерывание с помощью оператора break
Ветвления
Представление самого стандартного ветвления:
Представление работы else-if:
В Go также есть возможность использовать условные операторы с коротким обозначением переменной (:=
). Это позволяет нам объявить и присвоить значение переменной внутри условия if
Функции
Создание функций
Самая стандартная функция начинается с конструкции func
. Далее следует имя функции, её сигнатура, в которой указываются переменные и их тип. После сигнатуры указывается тип возвращаемого значения (если есть).
В теле функции выполняется повторяемый код. Если мы хотим что-то вернуть, то указываем return
Так же функция может вернуть сразу несколько параметров
Вызов функций
Для вызова функции достаточно написать её имя, после которого следуют круглые скобки с аргументами
Передача параметров по значению
По умолчанию в Go параметры функции передаются по значению, то есть создается копия значения аргумента и эта копия используется внутри функции
Передача параметров по ссылке
Если требуется изменить значение переменной внутри функции и эти изменения должны отразиться на оригинальной переменной, то можно передать параметр по ссылке (указателю)
Отложенное выполнение
Ключевое слово defer
используется для отложенного выполнения функции или метода. Когда функция содержит инструкцию defer
, соответствующий вызов функции не выполняется немедленно, а откладывается до окончания выполнения текущей функции или блока.
Вот некоторые особенности defer
:
- Порядок выполнения: Если в функции используются несколько инструкций
defer
, они будут выполнены в порядке обратном их объявлению. - Захват аргументов: Аргументы функции, передаваемые в инструкцию
defer
, вычисляются немедленно при объявленииdefer
. - Аргументы функции считываются заранее: Если аргументы функции, передаваемые в
defer
, подвержены изменениям до момента выполнения отложенной функции, то отложенная функция все равно получит их исходные значения, а не значения на момент вызова. - Работа с файлами и ресурсами:
defer
часто используется для освобождения ресурсов, таких как закрытие файла или соединения с базой данных, чтобы гарантировать, что эти ресурсы будут корректно освобождены независимо от пути выполнения функции.
В этом примере отложенный вызов file.Close()
гарантирует, что файл будет закрыт независимо от того, как завершится функция readFile()
. Это помогает избежать утечек ресурсов и обеспечивает более безопасное и удобное управление ресурсами.
Срезы, массивы и map
Массивы
Объявление и использование массивов. Массивы хранят в себе только тот тип данных, который мы указали
Слайсы
Слайс - это динамический массив, который не имеет определённого количества элементов
Слайс имеет определённые особенности при его использовании
Map
Карта - это ассоциативный массив, который представляет собой хеш-таблицу
Ключи и значения имеют одинаковый тип данных
Структуры и методы
структуры
Структура - это набор различных типов данных, которые описывают единый объект
Имя поля с заглавной - экспортируется, со строчной - не экспортируется и не может быть отображено в другом пакете вне данного
Далее в любую другую переменную мы можем записать экземпляр структуры Human
Методы
Базовая структура
Метод - это функция, которая привязана к определённой структуре. То есть для вызова метода, нужно создать соответствующую структуру
В приведенном примере мы создаем два метода на структуре Person
. Нужно обратить внимание, что имя структуры указывается перед именем метода в скобках - это ресивер (приёмник) - он обозначает привязанность метода к структуре.
Первый метод называется GetName()
и возвращает значение поля Name
структуры Person
. Второй метод называется SetAge(age int)
и устанавливает поле Age
структуры Person
в указанное значение age
.
Во втором случае мы использовали указатель, так как нам нужно получить доступ (ссылку) к объекту структуры и изменить его значение. В первом случае мы не использовали указатель, так как нам нужно только отобразить имя
Чтобы использовать структуры и их методы, мы можем создать экземпляр структуры и вызвать методы на этом экземпляре
Конструктор
Иногда, когда нам нужно будет создавать объект по структуре, мы можем сократить запись и реализовать конструктор, который может задавать определённые поля по умолчанию
Встраивание структуры
Структуры так же можно вкладывать друг друга, разбивая их данные
Так же есть и второй способ указания встроенной структуры, при котором поля уже будут принадлежать не отдельно структуре Parameters
, а именно Person
Занесение структуры
Указатели
Определение указателя
В Go указатель - это переменная, которая содержит адрес в памяти другой переменной. Через оператор *
мы указываем на ту переменную, которая будет являться указателем. Оператор &
используется для получения адреса переменной.
Разыменование указателя
В Go оператор *
используется для разыменования указателя и доступа к значению, на которое он указывает.
Изменение значения переменной через указатель
Поскольку указатель содержит адрес переменной, мы можем использовать его для изменения значения переменной напрямую
Передача указателя в функции
Указатели часто используются для передачи данных по ссылке в функции. При передаче указателя в функцию, изменения, сделанные внутри функции, будут отразиться на исходных переменных
Передача указателя в функции
Указатели часто используются для работы со значительными данными, такими как структуры. Создание указателей на структуры позволяет избежать копирования больших объемов данных при их передаче в функции
Интерфейсы
Создание интерфейса
Для создания интерфейса в Go необходимо объявить новый тип с набором методов, которые требуется реализовать. Например, предположим, что мы хотим создать интерфейс “Shape” для различных геометрических фигур:
Использование интерфейса
Затем можно создать структуры, которые реализуют этот интерфейс. Например, вот реализация интерфейса “Shape” для круга или “Square” для квадрата:
Обращение к интерфейсу
И теперь мы можем сделать обобщённую функцию, которая будет принимать в себя значения по интерфейсу
Итог
Таким образом, интерфейс - это структура, используемая для определения набора методов, которые тип должен реализовывать.
Чтобы воспользоваться интерфейсом, мы должны для структуры указать её методы, которые должны соответствовать интерфейсу по имени и типу возвращаемых данных
Интерфейс позволяет нам реализовать полиморфизм, так как мы можем указывать принимаемые аргументы в виде интерфейса.
Горутины и каналы
Горутины
Горутины (goroutines) в Go - это легковесные потоки выполнения, которые работают независимо друг от друга и могут быть запущены параллельно. Они позволяют выполнять асинхронные операции без явного создания отдельных потоков или процессов. Горутины разделяют общее пространство адресов и управляются сборщиком мусора, что делает их эффективными и недорогими в использовании.
Горутина - это функция, которая может быть запущена в отдельном потоке выполнения
Для создания горутины нужно просто передать функцию с ключевым словом go
Канал
Каналы (channels) служат для обмена данными между горутинами и обеспечивают синхронизацию и координацию выполнения параллельных процессов. Каналы можно представить как “трубы”, через которые горутины передают информацию. Они обеспечивают безопасный доступ к данным при параллельном выполнении, предотвращая состояние гонки (race condition) и другие проблемы синхронизации.
Каналы используются для обмена данными между горутинами
Каналы могут быть созданы с помощью функции make
Так же можно создать канал через стандартную запись
Затем вы можете отправлять и получать значения через канал, используя операторы <-
:
Каналы по умолчанию блокируют выполнение горутины при чтении или записи, пока другая горутина не будет готова для обмена. Это предотвращает состояние гонки (race condition) и делает программу безопасной для параллельного выполнения.
Кроме того, Go предлагает различные средства синхронизации, такие как мьютексы (mutexes) и условные переменные (condition variables), чтобы обеспечить правильную синхронизацию доступа к общим ресурсам и согласование работы горутин.
Буферизованный и небуферизованный канал
Небуферизованный канал может в себя принять ровно одно значение до того момента, пока его не прочитает горутина. Если горутина в другом месте кода не прочтёт значение из небуферизованного канала, то поток блокируется до того момента, пока его не начнут читать
Буферизованный канал в себе имеет уже выделенное нами количество ячеек под данные. Он так же блокируется, когда место под значения кончается. Если значение из него прочитали, то место под новые данные освобождается.
Использование горутин и каналов
В данном примере мы создаём канал resultChan
, который принимает в себя все просуммированные квадраты. Затем из этого канала мы достаём полученные значения функции.
Обработка ошибок
Ошибки
Errors: В Go ошибки представляются интерфейсом error
, который определен в стандартной библиотеке. Он имеет единственный метод Error() string
, который возвращает описание ошибки. Обычная практика возвращать ошибку в качестве значения последнего аргумента функции.
Проверка ошибок (Error Checking): Для проверки ошибок используется условное выражение, обычно с помощью if
или switch
. Пример:
Возврат ошибок (Returning Errors): Функции в Go могут возвращать ошибку вместе с другими значениями. Это позволяет вызывающему коду обрабатывать ошибку непосредственно. Пример:
Ошибки как значения (Errors as Values): Важно помнить, что в Go ошибки являются значениями, а не исключениями. Они должны быть явно обработаны кодом.
Паники
Паника (Panic): Паника - это серьезная ошибка, которая приводит к немедленной остановке выполнения программы. Когда возникает паника, выполнение обычно останавливается, и выводится стек вызовов (stack trace). Паника может возникать, например, при доступе к nil-указателю или при делении на ноль.
Восстановление (Recover): Чтобы предотвратить полную остановку программы при возникновении паники, можно использовать механизм восстановления (recover). Recover может быть использован только в отложенных функциях (deferred functions). Он возвращает значение типа interface{}
и используется для перехвата паники и возврата управления программе.
Упрощенное восстановление (Simplified Recovery): В Go 1.13 и более поздних версиях было добавлено упрощенное восстановление, которое позволяет перехватывать и обрабатывать панику в одной инструкции.
Пакеты и импорты
Тестирование
Работа с файлами и сетью
Развертывание приложений
Прочее
Веб-сервер на Golang
Самый простой веб-сервер:
Сборка и запуск веб-сервера под Windows и Linux
Чтобы собрать приложение под другую ОС, нужно указать в переменных окружения GOOS
и GOARCH