Skip to content

FinecoFinit/go-course

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Неделя 1. Введение в Go: Переменные, Ввод/Вывод и Основы

Что такое Go?

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

💡 Особенности:

  • Простота синтаксиса, как у Python
  • Производительность на уровне C
  • Встроенная конкурентность через goroutines
  • Идеально для серверной разработки, микросервисов, сетевых программ, CLI-инструментов

Установка Go


Go Workspace и структура проекта

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

Пример структуры:

amfs/
├── cmd/
│   └── amfs/        ← точка входа (main.go) для приложения
├── internal/        ← внутренние пакеты (нельзя импортировать извне)
├── pkg/             ← переиспользуемые публичные пакеты
├── go.mod           ← описание модуля и зависимостей
├── main.go          ← стартовый файл
└── other.go         ← дополнительные исходники

main() — точка входа

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


Компиляция и запуск

go mod init amfs       # инициализация модуля
go run main.go         # компиляция и запуск
go build               # компиляция → бинарный файл
go get <package>       # установка стороннего пакета

Пример:

go get github.com/shopspring/decimal

Переменные и константы

var x int = 10       // явное объявление
x := 10              // короткая форма (внутри функций)
const Pi = 3.14      // константа (нельзя изменить)

Типы данных

Категория Типы
Целые int, int8, int16, int32, int64
Беззнаковые uint, uint8, uint16, uint32, uint64
С плавающей точкой float32, float64
Логические bool
Строки string
Символы rune (аналог char, по сути int32)
Указатели *int, *string и т. д.
Обобщённый тип interface{}

⚠️ Никогда не используйте float для хранения финансов — используйте decimal.


Модуль fmt

Модуль fmt используется для ввода/вывода и форматирования.

Вывод:

fmt.Println("Hello")       // С пробелами и новой строкой
fmt.Printf("x = %d", 10)   // Форматированный вывод
s := fmt.Sprintf("Pi=%.2f", 3.1415) // Возврат строки

Ввод:

fmt.Scan(&x, &y)           // Считывает через пробел
fmt.Scanf("%d %s", &a, &b) // Форматированный ввод

Форматные спецификаторы:

Спецификатор Назначение
%d Целое число (int)
%f Число с плавающей точкой
%.2f Float с 2 знаками после запятой
%s Строка
%t Boolean
%v Значение как есть
%T Тип значения

Условные конструкции: if / else if / else

if a > b {
    fmt.Println("a больше b")
} else if a == b {
    fmt.Println("равны")
} else {
    fmt.Println("b больше a")
}
  • Скобки () не требуются!
  • Переменные можно объявлять внутри if:
if n := rand.Intn(10); n > 5 {
    fmt.Println("Большое:", n)
}

Переменная n не видна за пределами if.


Альтернатива ifswitch

switch выражение {
case значение1:
    // действие
case значение2:
    // другое действие
default:
    // если ничего не подошло
}

Пример:

type EComStatus uint8

const (
    New EComStatus = iota
    PreAuth
    Complete
    Declined
    Refunded
    Reversed
)

func (status EComStatus) IsValid() bool {
    switch status {
    case New, PreAuth, Complete, Declined, Refunded, Reversed:
        return true
    }
    return false
}

iota — генератор чисел в const-блоках

const (
    A = iota // 0
    B        // 1
    C        // 2
)

Полезен для:

  • Перечислений (enum)
  • Побитовых флагов
  • Автоматической генерации чисел

План задач по Go: Недельный модуль

Все задачи должны быть оформлены по базовой структуре проекта Go с соблюдением принципов DRY, KISS, SOLID.

Структура проекта:

project/
├── cmd/             # точка входа в приложение
├── internal/        # внутренняя логика
├── pkg/             # переиспользуемые пакеты
├── Makefile         # команды управления
├── .gitignore       # исключения для Git
├── .env             # переменные окружения (опционально)
├── .env.dist        # шаблон .env

Конвертер валют

Задача:

Создать мини-приложение, которое:

  1. Оформлено по структуре internal/pkg/cmd
  2. Совмещает в себе функционал двух предыдущих задач (в виде функций в отдельных модулях)
  3. Имеет Makefile с командами:
    • make run — запуск приложения
    • make build — сборка в ../bin
    • make link — проверка форматирования и статики (go fmt, go vet)
  4. Содержит .gitignore, .env, .env.dist — для будущих задач

Условия:

  • Использовать fmt для ввода и вывода
  • Использовать пакет shopspring/decimal

💡 Пример:

Вход:

15

Выход:

7800 KZT

Недельный расчет по операциям

Задача:

Обработать массив транзакций, где каждая — это map[int]decimal.Decimal, где:

  • int — номер дня недели (1 = Пн, 7 = Вс)
  • decimal.Decimal — сумма транзакции

Положительная сумма = доход, отрицательная = расход

Входные данные:

transactions := []map[int]decimal.Decimal{
 {1: decimal.NewFromFloat(25000.00)},
 {1: decimal.NewFromFloat(20000.00)},
 {2: decimal.NewFromFloat(-9800.00)},
 {3: decimal.NewFromFloat(-1222.22)},
 {4: decimal.NewFromFloat(-1500.07)},
 {5: decimal.NewFromFloat(1201.37)},
 {6: decimal.NewFromFloat(-100.32)},
 {7: decimal.NewFromFloat(-523.33)},
}

Требования:

  • Применить: for, if / else if / else, switch
  • Итоговый вывод:
    • День недели
    • Доход / Расход за день
    • Общий итог за неделю

Пример вывода:

Понедельник
Поступление: 45000.00

Вторник
Списание: 9800.00

Среда
Списание: 1222.22

Четверг
Списание: 1500.07

Пятница
Поступление: 1201.37

Суббота
Списание: 100.32

Воскресенье
Списание: 523.33

Итог за неделю: -10844.57

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


Неделя 2. Массивы, Слайсы, Мапы, Функции, Указатели, Структуры, Множества


Массивы

Массив — это фиксированная по длине коллекция однотипных элементов. Длина массива является частью его типа.

var a [3]int       // массив из трёх int, по умолчанию [0, 0, 0]
a[0] = 10          // установка значения
fmt.Println(a[1])  // доступ к элементу: 0
  • Тип [3]int и [4]int — разные типы.
  • Массивы копируются по значению.
  • Можно итерировать через for i, v := range a
  • Нельзя изменить длину массива после создания.
  • Внутри range — копия массива (если не использовать указатель).

Слайсы (Slices)

Слайс — это обёртка над массивом, включающая длину и ёмкость.

b := []int{1, 2, 3}
b = append(b, 4)
  • len(b) — текущая длина, cap(b) — ёмкость.
  • append может выделить новую память.
  • Слайсы передаются по ссылке.
  • Срезы: b[1:3], b[:2], b[2:]
  • Можно делать срез от среза: b2 := b[1:]

Map (словари / ассоциативные массивы)

m := make(map[string]int)
m["apple"] = 5
val, ok := m["apple"]
delete(m, "apple")
  • Проверка ключа: val, ok := m["key"]
  • Удаление: delete(m, "key")
  • Порядок итерации не гарантируется.
  • Ключи — сравнимые типы.
  • Значения — любые типы.

Функции

Функции — основной строительный блок в Go.

Объявление функции

func Add(a int, b int) int {
    return a + b
}

Несколько возвращаемых значений

func Swap(x, y string) (string, string) {
    return y, x
}

Именованные возвращаемые значения

func NamedReturn() (a int, b int) {
    a = 1
    b = 2
    return
}

Функции как значения

f := func(x int) int {
    return x * x
}
fmt.Println(f(5))

Анонимные функции

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

Замыкания

func Counter() func() int {
    count := 0
    return func() int {
        count++
        return count
    }
}

Функции высшего порядка

func Apply(fn func(int) int, val int) int {
    return fn(val)
}

Variadic-функции

func Sum(nums ...int) int {
    total := 0
    for _, n := range nums {
        total += n
    }
    return total
}

Рекурсия

func Factorial(n int) int {
    if n == 0 {
        return 1
    }
    return n * Factorial(n-1)
}

Указатели

func AddOne(x *int) {
    *x = *x + 1
}

val := 10
AddOne(&val)
fmt.Println(val) // 11
  • *x — разыменование
  • &val — получение адреса
  • Nil-указатели: var p *int

Структуры (Struct)

type User struct {
    Name string
    Age  int
}

u := User{Name: "Alice", Age: 30}
fmt.Println(u.Name)
  • Можно создавать указатели u := &User{}
  • Сравнимы, если все поля сравнимы

Множества (Set)

set := make(map[string]struct{})
set["apple"] = struct{}{}
_, ok := set["apple"]
delete(set, "apple")
  • Тип struct{} — 0 байт
  • Проверка: _, ok := set[key]

Проект: Сервис учёта транзакций мерчантов

Цель

Разработать Go-сервис, который:

  • Загружает конфигурацию через viper
  • Подключается к PostgreSQL
  • Автоматически мигрирует таблицы
  • Работает с транзакциями и статусами

Конфигурация

  • Порт приложения
  • DEBUG режим
  • Автомиграция
  • Данные БД
  • Docker переменные
  • .env.dist как пример

Структура БД

Таблица: terminals

Поле Тип данных Описание
id UUID (PK) Уникальный ID
client_id TEXT ID клиента
client_secret TEXT Секретный ключ
uuid TEXT Активен ли

Таблица: transactions

Поле Тип Описание
id UUID ID транзакции
terminal_id UUID FK на терминал
order_id TEXT ID клиента
amount NUMERIC(12,2) Сумма
status TEXT Статус
created_at TIMESTAMP Создана
status_changed TIMESTAMP Статус изменён
code TEXT Код
message TEXT Сообщение

Статусы транзакций

Статус Описание
REFUND Возврат суммы
AUTH Блокировка суммы
CANCEL Разблокировка
CHARGE Списание
VERIFIED Проверка карты
CANCEL_OLD Истёк срок CHARGE
FAILED Неуспешно
FINGERPRINT Проверка перед 3D
3D Ошибка 3D
NEW Ожидание
REJECT Отклонено

Логика перехода статусов

  1. NEWAUTH
  2. AUTHCHARGE или CANCEL
  3. CHARGEREFUND

Что реализовать

  • Глобальный конфиг через viper
  • Подключение к БД
  • Автомиграции (по флагу из конфига)
  • Создание транзакций и смена статусов

About

Go Course

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Go 93.0%
  • Makefile 7.0%