├── .gitignore ├── Часть 2. Продвинутый Golang и REST API ├── 12. Concurrency большой пример │ └── 1. Пример │ │ ├── go.mod │ │ ├── postman │ │ └── postman.go │ │ ├── main.go │ │ └── miner │ │ └── miner.go ├── 20. REST API. Теория и практика. │ └── 1. Список дел │ │ ├── go.mod │ │ ├── go.sum │ │ ├── todo │ │ ├── errors.go │ │ ├── task.go │ │ └── list.go │ │ ├── main.go │ │ └── http │ │ ├── dto.go │ │ ├── server.go │ │ └── handlers.go ├── 1. Интерфейсы │ ├── 2. Модуль проведения оплат │ │ ├── payments │ │ │ ├── info.go │ │ │ ├── methods │ │ │ │ ├── bank.go │ │ │ │ ├── paypal.go │ │ │ │ └── crypto.go │ │ │ └── payments.go │ │ ├── go.mod │ │ ├── main.go │ │ └── go.sum │ └── 1. Простой пример. Интерфейс Auto. │ │ └── main.go ├── 3. Паника │ ├── 2. Деление на ноль │ │ └── main.go │ ├── 1. Обращение к несущствующему элементу в слайсе │ │ └── main.go │ └── 3. Поимка паники │ │ └── main.go ├── 7. Закрытие каналов. Аксиомы каналов. │ ├── 1. Закрытие канала │ │ └── main.go │ ├── 6. Закрытие nil канала │ │ └── main.go │ ├── 2. Закрытие закрытого канала │ │ └── main.go │ ├── 4. Запись в закрытый канал │ │ └── main.go │ ├── 3. Чтение из закрытого канала │ │ └── main.go │ ├── 7. Чтение из nil канала. Запись в nil канал. │ │ └── main.go │ └── 5. Осмысленное закрытие канала │ │ └── main.go ├── 2. Обработка ошибок │ ├── 1. Функция возвращает только ошибку │ │ ├── go.mod │ │ ├── go.sum │ │ └── main.go │ └── 2. Функция возвращает значение и ошибку │ │ ├── go.mod │ │ ├── go.sum │ │ └── main.go ├── 17. HTTP методы │ ├── 1. Получение HTTP метода │ │ └── main.go │ └── 2. Обработка запросов только на определённом методе │ │ └── main.go ├── 16. HTTP хеддеры │ └── 1. Чтение HTTP хеддеров │ │ └── main.go ├── 19. Query параметры │ └── 1. Чтение query параметров │ │ └── main.go ├── 15. Тело HTTP ответа и HTTP статус коды │ ├── 1. Простая отправка HTTP ответа │ │ └── main.go │ ├── 2. Просто отправка нестандартных HTTP статус кодов в ответе │ │ └── main.go │ └── 3. Управление финансами │ │ └── main.go ├── 13. Первый HTTP сервер │ ├── 1. Hello, World! │ │ └── main.go │ ├── 3. Спящий хендлер │ │ └── main.go │ └── 2. Несколько хендлеров │ │ └── main.go ├── 5. Анонимные функции в горутинах │ └── 1. Пример анонимной функции в горутине │ │ └── main.go ├── 14. Тело HTTP запроса │ ├── 1. Простое чтение тела HTTP запроса │ │ └── main.go │ └── 2. Управление финансами │ │ └── main.go ├── 6. Конструкция select {} │ ├── 1. Ожидание значений из двух каналов │ │ └── main.go │ ├── 3. select + default │ │ └── main.go │ └── 2. Ожидание сообщений от двух друзей │ │ └── main.go ├── 4. Горутины и каналы │ ├── 1. Один шахтёр │ │ └── main.go │ └── 2. Несколько шахтёров │ │ └── main.go ├── 10. Гонка данных. Атомики. Мьютексы. │ ├── 2. Атомики │ │ └── main.go │ ├── 1. Гонка данных при увеличении целочисленной переменной │ │ └── main.go │ ├── 3. Гонка данных при добавлении новых элементов в слайс │ │ └── main.go │ └── 4. Мьютексы │ │ └── main.go ├── 9. WaitGroup │ └── 1. Ожидание почтальонов │ │ └── main.go ├── 11. RWMutex │ └── 1. Ставим лайки │ │ └── main.go ├── 8. Контекст │ └── 1. Контроль выполнения разных групп горутин │ │ └── main.go └── 18. JSON │ └── 1. Приём и передача комплексной информации по HTTP │ └── main.go ├── Часть 1. Основы программирования ├── 1. Первая программа │ ├── 1. Пустая программа │ │ └── main.go │ ├── 3. fmt.Print │ │ └── main.go │ └── 2. fmt.Println │ │ └── main.go ├── 9. Модули и пакеты │ ├── 2. Модуль с пакетами │ │ ├── user │ │ │ ├── human.go │ │ │ └── user.go │ │ ├── greeting │ │ │ ├── foo │ │ │ │ └── somefile.go │ │ │ ├── greeting.go │ │ │ └── givemeint.go │ │ ├── go.mod │ │ ├── main.go │ │ └── go.sum │ └── 1. Простой модуль из одного main-пакета │ │ ├── main.go │ │ ├── go.mod │ │ └── go.sum ├── 4. Циклы │ ├── 1. Обычный цикл for │ │ └── main.go │ ├── 3. Flappy Bird генерация уровней │ │ └── main.go │ ├── 2. Flappy Bird симуляция │ │ └── main.go │ └── 4. Flappy Bird продвинутая симуляция │ │ └── main.go ├── 6. defer() │ ├── 1. Обычный defer() │ │ └── main.go │ ├── 2. Множественный defer() │ │ └── main.go │ └── 3. defer() в других функциях │ │ └── main.go ├── 3. Условные ветвления │ ├── 5. Оператор логического отрицания │ │ └── main.go │ ├── 1. if-else │ │ └── main.go │ ├── 2. if-elseif-else │ │ └── main.go │ ├── 4. Оператор И │ │ └── main.go │ └── 3. Оператор ИЛИ │ │ └── main.go ├── 7. Указатели │ ├── 1. Принятие указателя в функции │ │ └── main.go │ ├── 2. Изменение значения переменной через указатель │ │ └── main.go │ └── 3. nil pointer │ │ └── main.go ├── 2. Переменные │ ├── 1. Создание переменных через короткую запись │ │ └── main.go │ ├── 2. Создание переменных через длинную запись │ │ └── main.go │ └── 3. Операции над переменными │ │ └── main.go ├── 5. Функции │ ├── 5. return в функции, которая ничего не возвращает │ │ └── main.go │ ├── 6. Глобальные переменные │ │ └── main.go │ ├── 2. Функция принимает значение, но ничего не возвращает │ │ └── main.go │ ├── 1. Функция ничего не принимает и ничего не возвращает │ │ └── main.go │ ├── 3. Изменение значений внутри функций │ │ └── main.go │ └── 4. Функция принимает и возвращает какие-то значения │ │ └── main.go ├── 10. Массивы Слайсы Мапы │ ├── 2. Слайс │ │ ├── go.mod │ │ ├── go.sum │ │ └── main.go │ ├── 3. Мапа │ │ └── main.go │ └── 1. Массив │ │ └── main.go ├── 8. Структуры │ ├── 2. Ресивер по значению и по указателю │ │ └── main.go │ ├── 1. Структура User без методов │ │ └── main.go │ └── 3. Структура User с методами и конструктором │ │ └── main.go └── 11. Пользовательский ввод │ └── 1. Чтение пользовательского ввода │ └── main.go └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_STORE 2 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/12. Concurrency большой пример/1. Пример/go.mod: -------------------------------------------------------------------------------- 1 | module concurrency 2 | 3 | go 1.24.1 4 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/1. Первая программа/1. Пустая программа/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/20. REST API. Теория и практика./1. Список дел/go.mod: -------------------------------------------------------------------------------- 1 | module restapi 2 | 3 | go 1.24.1 4 | 5 | require github.com/gorilla/mux v1.8.1 6 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/9. Модули и пакеты/2. Модуль с пакетами/user/human.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | // private // private (because of lower case of first letter) 4 | type human struct{} 5 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/9. Модули и пакеты/2. Модуль с пакетами/greeting/foo/somefile.go: -------------------------------------------------------------------------------- 1 | package foo 2 | 3 | import "math/rand" 4 | 5 | func RandomFunc() int { 6 | return rand.Intn(10) 7 | } 8 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/4. Циклы/1. Обычный цикл for/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | for i := 1; i <= 5; i++ { 7 | fmt.Println("Hello, World!") 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/9. Модули и пакеты/2. Модуль с пакетами/greeting/greeting.go: -------------------------------------------------------------------------------- 1 | package greeting 2 | 3 | import "fmt" 4 | 5 | func SayHello() { 6 | fmt.Println("Hello from 'greeting' package!") 7 | } 8 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/1. Интерфейсы/2. Модуль проведения оплат/payments/info.go: -------------------------------------------------------------------------------- 1 | package payments 2 | 3 | type PaymentsInfo struct { 4 | Description string 5 | USD int 6 | Cancelled bool 7 | } 8 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/3. Паника/2. Деление на ноль/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | number := 0 7 | 8 | i := 10 / number 9 | 10 | fmt.Println("i:", i) 11 | } 12 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/1. Первая программа/3. fmt.Print/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | fmt.Print("Hello, World!") 7 | fmt.Print("How are you doing?") 8 | fmt.Print("Лампочка") 9 | } 10 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/6. defer()/1. Обычный defer()/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | defer func() { 7 | fmt.Println("Defer Println") 8 | }() 9 | 10 | fmt.Println("hello") 11 | } 12 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/1. Первая программа/2. fmt.Println/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | fmt.Println("Hello, World!") 7 | fmt.Println("How are you doing?") 8 | fmt.Println("Лампочка") 9 | } 10 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/20. REST API. Теория и практика./1. Список дел/go.sum: -------------------------------------------------------------------------------- 1 | github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= 2 | github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= 3 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/20. REST API. Теория и практика./1. Список дел/todo/errors.go: -------------------------------------------------------------------------------- 1 | package todo 2 | 3 | import "errors" 4 | 5 | var ErrTaskNotFound = errors.New("task not found") 6 | var ErrTaskAlreadyExists = errors.New("task already exists") 7 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/3. Условные ветвления/5. Оператор логического отрицания/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | subscribed := true 7 | 8 | if !subscribed { 9 | fmt.Println("Я вижу ты не подписан! Подпишись, пожалуйста!") 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/9. Модули и пакеты/2. Модуль с пакетами/greeting/givemeint.go: -------------------------------------------------------------------------------- 1 | package greeting 2 | 3 | // public 4 | func GiveMeInt() int { 5 | return 55 6 | } 7 | 8 | // private (because of lower case of first letter) 9 | func giveMeInt() int { 10 | return 55 11 | } 12 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/3. Паника/1. Обращение к несущствующему элементу в слайсе/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | // [0] [1] [2] 7 | slice := []int{11, 22, 33} 8 | 9 | i := slice[3] 10 | 11 | fmt.Println("i:", i) 12 | } 13 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/3. Условные ветвления/1. if-else/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | score := 12 7 | 8 | if score > 10 { 9 | fmt.Println("Ты красавчик!") 10 | } else { 11 | fmt.Println("Тебе нужно ещё многому научиться.") 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/7. Закрытие каналов. Аксиомы каналов./1. Закрытие канала/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | // Создали канал. Сразу после создания канал всегда открыт. 5 | ch := make(chan int) 6 | 7 | // Закрыли канал. Теперь он закрытый. 8 | close(ch) 9 | } 10 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/7. Закрытие каналов. Аксиомы каналов./6. Закрытие nil канала/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | // Создали nil канал. nil потому что не проинициализирован через make 5 | var ch chan int 6 | 7 | // Закрываем nil канал. Получаем панику. 8 | close(ch) 9 | } 10 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/9. Модули и пакеты/1. Простой модуль из одного main-пакета/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/k0kubun/pp" 4 | 5 | type User struct { 6 | Name string 7 | Age int 8 | } 9 | 10 | func main() { 11 | user := User{ 12 | Name: "Василий", 13 | Age: 67, 14 | } 15 | 16 | pp.Println(user) 17 | } 18 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/6. defer()/2. Множественный defer()/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | defer func() { 7 | fmt.Println("Defer1") 8 | }() 9 | 10 | defer func() { 11 | fmt.Println("Defer2") 12 | }() 13 | 14 | defer func() { 15 | fmt.Println("Defer3") 16 | }() 17 | 18 | fmt.Println("hello") 19 | } 20 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/3. Условные ветвления/2. if-elseif-else/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | score := 20 7 | 8 | if score > 15 { 9 | fmt.Println("Ты мега-красавчик!") 10 | } else if score > 10 { 11 | fmt.Println("Ты красавчик!") 12 | } else { 13 | fmt.Println("Тебе нужно ещё многому научиться.") 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/7. Указатели/1. Принятие указателя в функции/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | number := 5 7 | 8 | ptr := &number 9 | 10 | foo(ptr) 11 | } 12 | 13 | func foo(intPtr *int) { 14 | fmt.Println("Указатель:", intPtr) 15 | fmt.Println("Значение переменной, на которую указатель указывает:", *intPtr) 16 | } 17 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/7. Закрытие каналов. Аксиомы каналов./2. Закрытие закрытого канала/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | // Создали канал. Сразу после создания канал всегда открыт. 5 | ch := make(chan int) 6 | 7 | // Закрыли канал. Теперь он закрытый. 8 | close(ch) 9 | 10 | // Закрываем уже закрытый канал. Получаем панику. 11 | close(ch) 12 | } 13 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/7. Закрытие каналов. Аксиомы каналов./4. Запись в закрытый канал/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | // Создали канал. Сразу после создания канал всегда открыт. 5 | ch := make(chan int) 6 | 7 | // Закрыли канал. Теперь он закрытый. 8 | close(ch) 9 | 10 | // Запись в закрытый канал. 11 | // Получим панику. 12 | ch <- 10 13 | } 14 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/2. Переменные/1. Создание переменных через короткую запись/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | number := 15 7 | text := "Hello" 8 | drob := 11.25 9 | boolean := true 10 | 11 | fmt.Println("number:", number) 12 | fmt.Println("text:", text) 13 | fmt.Println("drob:", drob) 14 | fmt.Println("boolean:", boolean) 15 | } 16 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/5. Функции/5. return в функции, которая ничего не возвращает/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | greeting("") 7 | greeting("Иван") 8 | } 9 | 10 | func greeting(name string) { 11 | if name == "" { 12 | fmt.Println("Вы передали пустое имя.") 13 | return 14 | } 15 | 16 | fmt.Println("Привет, уважаемый", name) 17 | } 18 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/5. Функции/6. Глобальные переменные/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // 10 6 | var number int = 10 7 | 8 | func main() { 9 | // 15 10 | number += 5 11 | 12 | foo() 13 | boo() 14 | 15 | fmt.Println("number:", number) 16 | } 17 | 18 | func foo() { 19 | // 30 20 | number *= 2 21 | } 22 | 23 | func boo() { 24 | // 3 25 | number /= 10 26 | } 27 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/5. Функции/2. Функция принимает значение, но ничего не возвращает/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | fmt.Println("До вызова функции square(x int)") 7 | square(5) 8 | fmt.Println("После вызова функции square(x int)") 9 | } 10 | 11 | func square(x int) { 12 | fmt.Println("Принято значение x:", x) 13 | fmt.Println("x в квадрате:", x*x) 14 | } 15 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/10. Массивы Слайсы Мапы/2. Слайс/go.mod: -------------------------------------------------------------------------------- 1 | module study 2 | 3 | go 1.24.1 4 | 5 | require github.com/k0kubun/pp v3.0.1+incompatible 6 | 7 | require ( 8 | github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect 9 | github.com/mattn/go-colorable v0.1.14 // indirect 10 | github.com/mattn/go-isatty v0.0.20 // indirect 11 | golang.org/x/sys v0.29.0 // indirect 12 | ) 13 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/3. Условные ветвления/4. Оператор И/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | sunny := true 7 | weekend := true 8 | 9 | // Я пойду гулять, только если будет солнечная погода и будет выходной, 10 | // иначе я никуда не пойду 11 | 12 | if sunny && weekend { 13 | fmt.Println("Я иду гулять!") 14 | } else { 15 | fmt.Println("Я НЕ пойду гулять (") 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/9. Модули и пакеты/2. Модуль с пакетами/go.mod: -------------------------------------------------------------------------------- 1 | module study 2 | 3 | go 1.24.1 4 | 5 | require github.com/k0kubun/pp v3.0.1+incompatible 6 | 7 | require ( 8 | github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect 9 | github.com/mattn/go-colorable v0.1.14 // indirect 10 | github.com/mattn/go-isatty v0.0.20 // indirect 11 | golang.org/x/sys v0.29.0 // indirect 12 | ) 13 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/1. Интерфейсы/2. Модуль проведения оплат/go.mod: -------------------------------------------------------------------------------- 1 | module interfaces 2 | 3 | go 1.24.1 4 | 5 | require github.com/k0kubun/pp v3.0.1+incompatible 6 | 7 | require ( 8 | github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect 9 | github.com/mattn/go-colorable v0.1.14 // indirect 10 | github.com/mattn/go-isatty v0.0.20 // indirect 11 | golang.org/x/sys v0.29.0 // indirect 12 | ) 13 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/9. Модули и пакеты/1. Простой модуль из одного main-пакета/go.mod: -------------------------------------------------------------------------------- 1 | module study 2 | 3 | go 1.24.1 4 | 5 | require github.com/k0kubun/pp v3.0.1+incompatible 6 | 7 | require ( 8 | github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect 9 | github.com/mattn/go-colorable v0.1.14 // indirect 10 | github.com/mattn/go-isatty v0.0.20 // indirect 11 | golang.org/x/sys v0.29.0 // indirect 12 | ) 13 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/2. Обработка ошибок/1. Функция возвращает только ошибку/go.mod: -------------------------------------------------------------------------------- 1 | module study 2 | 3 | go 1.24.1 4 | 5 | require github.com/k0kubun/pp v3.0.1+incompatible 6 | 7 | require ( 8 | github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect 9 | github.com/mattn/go-colorable v0.1.14 // indirect 10 | github.com/mattn/go-isatty v0.0.20 // indirect 11 | golang.org/x/sys v0.29.0 // indirect 12 | ) 13 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/2. Обработка ошибок/2. Функция возвращает значение и ошибку/go.mod: -------------------------------------------------------------------------------- 1 | module study 2 | 3 | go 1.24.1 4 | 5 | require github.com/k0kubun/pp v3.0.1+incompatible 6 | 7 | require ( 8 | github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect 9 | github.com/mattn/go-colorable v0.1.14 // indirect 10 | github.com/mattn/go-isatty v0.0.20 // indirect 11 | golang.org/x/sys v0.29.0 // indirect 12 | ) 13 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/5. Функции/1. Функция ничего не принимает и ничего не возвращает/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | fmt.Println("До вызова функции hello()") 7 | hello() 8 | fmt.Println("После вызова функции hello()") 9 | } 10 | 11 | func hello() { 12 | fmt.Println("Я функция hello, я начинаюсь!") 13 | fmt.Println("Я фукнция hello, я продолжаюсь!") 14 | fmt.Println("Я функция hello, я заканчиваюсь!") 15 | } 16 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/5. Функции/3. Изменение значений внутри функций/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | number := 5 7 | text := "hello" 8 | 9 | fmt.Println("number до:", number) 10 | fmt.Println("text до:", text) 11 | 12 | foo(number, text) 13 | 14 | fmt.Println("number после:", number) 15 | fmt.Println("text после:", text) 16 | 17 | } 18 | 19 | func foo(n int, t string) { 20 | n = 10 21 | t = "world" 22 | } 23 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/20. REST API. Теория и практика./1. Список дел/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "restapi/http" 6 | "restapi/todo" 7 | ) 8 | 9 | func main() { 10 | todoList := todo.NewList() 11 | httpHandlers := http.NewHTTPHandlers(todoList) 12 | httpServer := http.NewHTTPServer(httpHandlers) 13 | 14 | if err := httpServer.StartServer(); err != nil { 15 | fmt.Println("failed to start http server:", err) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/9. Модули и пакеты/2. Модуль с пакетами/user/user.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | // public 4 | type User struct { 5 | // public 6 | Name string 7 | 8 | // private (because of lower case of first letter) 9 | age int 10 | } 11 | 12 | // public 13 | func (u *User) ChangeAge(newAge int) { 14 | u.age = newAge 15 | } 16 | 17 | // private (because of lower case of first letter) 18 | func (u *User) changeName(newName string) { 19 | u.Name = newName 20 | } 21 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/3. Условные ветвления/3. Оператор ИЛИ/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | computerClub := true 7 | icecream := true 8 | 9 | // Я пойду гулять, если там либо будет компьютерный клуб 10 | // либо если там будет мороженное. 11 | // Если там не будет ни того ни другого, я никуда не пойду 12 | 13 | if computerClub || icecream { 14 | fmt.Println("Я иду гулять!") 15 | } else { 16 | fmt.Println("Я НЕ пойду гулять (") 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/17. HTTP методы/1. Получение HTTP метода/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func handler(w http.ResponseWriter, r *http.Request) { 9 | fmt.Println("Метод входящего HTTP запроса:", r.Method) 10 | } 11 | 12 | func main() { 13 | http.HandleFunc("/default", handler) 14 | 15 | fmt.Println("Запускаю HTTP сервер!") 16 | err := http.ListenAndServe(":9091", nil) 17 | if err != nil { 18 | fmt.Println("Ошибка во время работы HTTP сервера:", err) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/4. Циклы/3. Flappy Bird генерация уровней/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | // 🔋 7 | // 🛢 8 | // 🐤 9 | 10 | fmt.Println("Начинаю генерировать уровень!") 11 | fmt.Println("") 12 | 13 | for i := 1; i <= 5; i++ { 14 | fmt.Println("Труба номер", i) 15 | fmt.Println("----") 16 | 17 | if i%2 == 0 { 18 | fmt.Println("🛢🛢") 19 | } else { 20 | fmt.Println("🔋🔋") 21 | } 22 | 23 | fmt.Println("----") 24 | fmt.Println("") 25 | } 26 | 27 | fmt.Println("Генерация уровня окончена!") 28 | } 29 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/8. Структуры/2. Ресивер по значению и по указателю/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type User struct { 6 | Age int 7 | } 8 | 9 | func (u User) ChangeAge1(newAge int) { 10 | u.Age = newAge 11 | } 12 | 13 | func (u *User) ChangeAge2(newAge int) { 14 | u.Age = newAge 15 | } 16 | 17 | func main() { 18 | user := User{ 19 | Age: 30, 20 | } 21 | 22 | fmt.Println("user изначально:", user) 23 | user.ChangeAge1(35) 24 | fmt.Println("user после ChangeAge1:", user) 25 | user.ChangeAge2(35) 26 | fmt.Println("user после ChangeAge2:", user) 27 | } 28 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/7. Закрытие каналов. Аксиомы каналов./3. Чтение из закрытого канала/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | // Создали канал. Сразу после создания канал всегда открыт. 7 | ch := make(chan int) 8 | 9 | // Закрыли канал. Теперь он закрытый. 10 | close(ch) 11 | 12 | // Читаем из закрытого канала. 13 | // Получаем значение по умолчанию. 14 | // В опциональной переменной ok лежит false (что означает, что было прочитано значение по умолчанию, что означает что канал был закрыт) 15 | v, ok := <-ch 16 | 17 | fmt.Println("v:", v, "ok:", ok) 18 | } 19 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/3. Паника/3. Поимка паники/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func panicSlice() { 6 | slice := []int{11, 22, 33} 7 | 8 | i := slice[3] 9 | 10 | fmt.Println("i:", i) 11 | } 12 | 13 | func panicDivision() { 14 | number := 0 15 | 16 | i := 10 / number 17 | 18 | fmt.Println("i:", i) 19 | } 20 | 21 | func main() { 22 | defer func() { 23 | p := recover() 24 | if p != nil { 25 | fmt.Println("Была отловлена паника:", p) 26 | } 27 | }() 28 | 29 | // panicSlice() 30 | // panicDivision() 31 | 32 | fmt.Println("Конец выполнения программы!") 33 | } 34 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/7. Указатели/2. Изменение значения переменной через указатель/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | number := 5 7 | numberPtr := &number 8 | 9 | fmt.Println("number до вызова foo:", number) 10 | foo(numberPtr) 11 | fmt.Println("number после вызова foo:", number) 12 | 13 | text := "hello" 14 | textPtr := &text 15 | 16 | fmt.Println("text до вызова foo:", text) 17 | boo(textPtr) 18 | fmt.Println("text после вызова foo:", text) 19 | } 20 | 21 | func foo(intPtr *int) { 22 | *intPtr = 10 23 | } 24 | 25 | func boo(stringPtr *string) { 26 | *stringPtr = "world" 27 | } 28 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/5. Функции/4. Функция принимает и возвращает какие-то значения/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | number1 := 25 7 | number2 := 17 8 | 9 | resultNumber := sumInt(number1, number2) 10 | 11 | fmt.Println("number1 + number2 ==", resultNumber) 12 | 13 | text1 := "hello" 14 | text2 := "world" 15 | 16 | resultText := sumText(text1, text2) 17 | 18 | fmt.Println("text1 + text2 ==", resultText) 19 | } 20 | 21 | func sumInt(a int, b int) int { 22 | s := a + b 23 | 24 | return s 25 | } 26 | 27 | func sumText(s1 string, s2 string) string { 28 | s := s1 + s2 29 | 30 | return s 31 | } 32 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/9. Модули и пакеты/2. Модуль с пакетами/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "study/greeting" 6 | "study/greeting/foo" 7 | "study/user" 8 | 9 | "github.com/k0kubun/pp" 10 | ) 11 | 12 | func main() { 13 | greeting.SayHello() 14 | i := greeting.GiveMeInt() 15 | fmt.Println("i:", i) 16 | 17 | rand := foo.RandomFunc() 18 | fmt.Println("rand:", rand) 19 | 20 | u := user.User{ 21 | Name: "Григорий", 22 | // age не видно, потому что age private 23 | } 24 | 25 | u.ChangeAge(50) 26 | // changeName не видно, потому что changeName private 27 | // user.changeName 28 | 29 | pp.Println("user:", u) 30 | } 31 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/16. HTTP хеддеры/1. Чтение HTTP хеддеров/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func handler(w http.ResponseWriter, r *http.Request) { 9 | for k, v := range r.Header { 10 | fmt.Println("Название хеддера:", k, "-- значение, лежащее в хеддере:", v) 11 | } 12 | 13 | fmt.Println("payHandler закончил своё выполнение.") 14 | } 15 | 16 | func main() { 17 | http.HandleFunc("/default", handler) 18 | 19 | fmt.Println("Запускаю HTTP сервер!") 20 | err := http.ListenAndServe(":9091", nil) 21 | if err != nil { 22 | fmt.Println("Ошибка во время работы HTTP сервера:", err) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/19. Query параметры/1. Чтение query параметров/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func handler(w http.ResponseWriter, r *http.Request) { 9 | fooParam := r.URL.Query().Get("foo") 10 | booParam := r.URL.Query().Get("boo") 11 | 12 | fmt.Println("foo параметр:", fooParam) 13 | fmt.Println("boo параметр:", booParam) 14 | } 15 | 16 | func main() { 17 | http.HandleFunc("/default", handler) 18 | 19 | fmt.Println("Запускаю HTTP сервер!") 20 | err := http.ListenAndServe(":9091", nil) 21 | if err != nil { 22 | fmt.Println("Ошибка во время работы HTTP сервера:", err) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/7. Указатели/3. nil pointer/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | number := 15 7 | 8 | var notNilPtr *int = &number 9 | var nilPtr *int 10 | 11 | fmt.Print("Not nil pointer: ") 12 | foo(notNilPtr) 13 | 14 | fmt.Println("") 15 | 16 | fmt.Print("nil pointer: ") 17 | foo(nilPtr) 18 | } 19 | 20 | func foo(intPtr *int) { 21 | fmt.Println("Указатель:", intPtr) 22 | 23 | if intPtr != nil { 24 | fmt.Println("Значение переменной, на которую указывает указатель:", *intPtr) 25 | } else { 26 | fmt.Println("Указатель является nil-указателем, а значит я не могу его безопасно разыменовать") 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/7. Закрытие каналов. Аксиомы каналов./7. Чтение из nil канала. Запись в nil канал./main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | // Создали nil канал. nil потому что не проинициализирован через make 7 | var ch chan string 8 | // var ch chan string = make(chan string) // стоит проинициализировать через make, как сразу всё заработает 9 | 10 | go func() { 11 | // Запись в nil канал. Получаем блокировку. 12 | ch <- "hello" 13 | }() 14 | 15 | // Чтение из nil канала. Получаем блокировку. Все горутины заблокировались == deadlock. 16 | v := <-ch 17 | 18 | fmt.Println("Полученное из канала значение:", v) 19 | } 20 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/6. defer()/3. defer() в других функциях/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | defer func() { 7 | fmt.Println("main Defer1") 8 | }() 9 | defer func() { 10 | fmt.Println("main Defer2") 11 | }() 12 | defer func() { 13 | fmt.Println("main Defer3") 14 | }() 15 | 16 | fmt.Println("до вызова foo") 17 | foo() 18 | fmt.Println("после вызова foo") 19 | } 20 | 21 | func foo() { 22 | defer func() { 23 | fmt.Println("foo Defer1") 24 | }() 25 | 26 | defer func() { 27 | fmt.Println("foo Defer2") 28 | }() 29 | 30 | defer func() { 31 | fmt.Println("foo Defer3") 32 | }() 33 | 34 | fmt.Println("foo") 35 | } 36 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/2. Переменные/2. Создание переменных через длинную запись/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var number1 int = 15 7 | var text1 string = "Hello" 8 | var drob1 float64 = 11.25 9 | var boolean1 bool = true 10 | 11 | fmt.Println("number1:", number1) 12 | fmt.Println("text1:", text1) 13 | fmt.Println("dro1:", drob1) 14 | fmt.Println("boolean1:", boolean1) 15 | 16 | var number2 int 17 | var text2 string 18 | var drob2 float64 19 | var boolean2 bool 20 | 21 | fmt.Println("number2:", number2) 22 | fmt.Println("text2:", text2) 23 | fmt.Println("drob2:", drob2) 24 | fmt.Println("boolean2:", boolean2) 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/15. Тело HTTP ответа и HTTP статус коды/1. Простая отправка HTTP ответа/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func handler(w http.ResponseWriter, r *http.Request) { 9 | _, err := w.Write([]byte("This is my HTTP response!")) 10 | if err != nil { 11 | fmt.Println("Ошибка записи HTTP ответа:", err) 12 | return 13 | } 14 | 15 | fmt.Println("Успешно записал HTTP ответ!") 16 | } 17 | 18 | func main() { 19 | http.HandleFunc("/default", handler) 20 | 21 | fmt.Println("Запускаю HTTP сервер!") 22 | err := http.ListenAndServe(":9091", nil) 23 | if err != nil { 24 | fmt.Println("Ошибка во время работы HTTP сервера:", err) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Полный курс по Golang 2 | 3 | Первая часть курса:\ 4 | https://www.youtube.com/watch?v=dpvRDJjUJf8 5 | 6 | Вторая часть курса:\ 7 | https://www.youtube.com/watch?v=4xST8IWJFZc 8 | 9 | Приватное сообщество с домашними заданиями и учебными проектами:\ 10 | https://t.me/nilchanbot 11 | 12 | Телеграм канал:\ 13 | https://t.me/nilchanpub 14 | 15 | - К каждой пройденной теме прилагаются исходные коды с уроков 16 | - К каждой части полного курса по Golang **в приватном сообществе прилагаются домашние задания и задания на учебный проект**. Домашние задания служат для тренировки каждой отдельной пройденной темы. Учебные проекты служат крупной закрепляющей тренировкой всех пройденных в рамках каждой отдельной части тем. 17 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/13. Первый HTTP сервер/1. Hello, World!/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func handler(w http.ResponseWriter, r *http.Request) { 9 | str := "Hello, World!" 10 | b := []byte(str) 11 | 12 | _, err := w.Write(b) 13 | if err != nil { 14 | fmt.Println("Во время записи HTTP ответа произошла ошибка:", err) 15 | } else { 16 | fmt.Println("Я корректно обработал HTTP запрос") 17 | } 18 | } 19 | 20 | func main() { 21 | http.HandleFunc("/default", handler) 22 | 23 | fmt.Println("Запускаю HTTP сервер!") 24 | err := http.ListenAndServe(":9091", nil) 25 | if err != nil { 26 | fmt.Println("Ошибка во время работы HTTP сервера:", err) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/5. Анонимные функции в горутинах/1. Пример анонимной функции в горутине/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | // Обычная функция 9 | func foo() { 10 | for { 11 | fmt.Println("Foo") 12 | time.Sleep(500 * time.Millisecond) 13 | } 14 | } 15 | 16 | // main горутина 17 | func main() { 18 | // Запускаем обычную функцию в горутине 19 | go foo() 20 | 21 | // Запускаем анонимную функцию в горутине 22 | go func() { 23 | for { 24 | fmt.Println("Anon") 25 | time.Sleep(750 * time.Millisecond) 26 | } 27 | }() 28 | 29 | // Засыпаем на 5 секунд в main горутине, чтобы дать "Foo" и "Anon" горутинам поработать 30 | time.Sleep(5 * time.Second) 31 | } 32 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/15. Тело HTTP ответа и HTTP статус коды/2. Просто отправка нестандартных HTTP статус кодов в ответе/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func handler(w http.ResponseWriter, r *http.Request) { 9 | // w.WriteHeader(http.StatusBadRequest) 10 | // w.WriteHeader(http.StatusConflict) 11 | w.WriteHeader(http.StatusInternalServerError) 12 | 13 | fmt.Println("Успешно записал статус код в HTTP ответ!") 14 | } 15 | 16 | func main() { 17 | http.HandleFunc("/default", handler) 18 | 19 | fmt.Println("Запускаю HTTP сервер!") 20 | err := http.ListenAndServe(":9091", nil) 21 | if err != nil { 22 | fmt.Println("Ошибка во время работы HTTP сервера:", err) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/1. Интерфейсы/2. Модуль проведения оплат/payments/methods/bank.go: -------------------------------------------------------------------------------- 1 | package methods 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | ) 7 | 8 | // Заглушка, иммитирующая проведение оплаты через банк 9 | type Bank struct{} 10 | 11 | func NewBank() Bank { 12 | return Bank{} 13 | } 14 | 15 | func (b Bank) Pay(usd int) int { 16 | // Иммитируем проведения оплаты через банк 17 | fmt.Println("Оплата через банк!") 18 | fmt.Println("Размер оплаты:", usd, "долларов") 19 | 20 | // Генерируем и возвращаем рандомный ID оплаты 21 | return rand.Int() 22 | } 23 | 24 | func (b Bank) Cancel(id int) { 25 | // Иммитируем отмену оплаты с переданным ID через банк 26 | fmt.Println("Отмена банковской операции! ID:", id) 27 | } 28 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/4. Циклы/2. Flappy Bird симуляция/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | // 🔋 7 | // 🐤 8 | 9 | score := 0 10 | 11 | fmt.Println("Get Ready") 12 | fmt.Println("Счёт:", score) 13 | fmt.Println("") 14 | 15 | for i := 1; i <= 10; i++ { 16 | fmt.Println("---------------------") 17 | fmt.Println("Вы подлетаете к трубе!", i) 18 | fmt.Println("🐤 🔋🔋") 19 | fmt.Println("") 20 | 21 | fmt.Println("Вы пролетаете через трубу!", i) 22 | fmt.Println("🔋🐤🔋") 23 | fmt.Println("") 24 | 25 | fmt.Println("Вы пролетели через трубу!", i) 26 | fmt.Println("🔋🔋 🐤") 27 | fmt.Println("") 28 | 29 | score++ 30 | 31 | fmt.Println("Счёт:", score) 32 | fmt.Println("") 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/2. Переменные/3. Операции над переменными/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | number := 15 7 | text := "Hello" 8 | drob := 11.25 9 | boolean := true 10 | 11 | // сложение 12 | number = number + 10 13 | number += 15 14 | number++ 15 | 16 | // умножение 17 | number = number * 100 18 | number *= 5 19 | 20 | // деление 21 | number = number / 10 22 | number /= 5 23 | 24 | // вычитание 25 | drob = drob - 1.05 26 | drob -= 4.2 27 | drob-- 28 | 29 | // конкатенация 30 | text = text + "World" 31 | text += "!" 32 | 33 | // вывод в консоль 34 | fmt.Println("number:", number) 35 | fmt.Println("text:", text) 36 | fmt.Println("drob:", drob) 37 | fmt.Println("boolean:", boolean) 38 | } 39 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/1. Интерфейсы/2. Модуль проведения оплат/payments/methods/paypal.go: -------------------------------------------------------------------------------- 1 | package methods 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | ) 7 | 8 | // Заглушка, иммитирующая проведение оплаты через PayPal 9 | type PayPal struct{} 10 | 11 | func NewPayPal() PayPal { 12 | return PayPal{} 13 | } 14 | 15 | func (p PayPal) Pay(usd int) int { 16 | // Иммитируем проведения оплаты через PayPal 17 | fmt.Println("Оплата через PayPal!") 18 | fmt.Println("Размер оплаты:", usd, "usd") 19 | 20 | // Генерируем и возвращаем рандомный ID оплаты 21 | return rand.Int() 22 | } 23 | 24 | func (p PayPal) Cancel(id int) { 25 | // Иммитируем отмену оплаты с переданным ID через PayPal 26 | fmt.Println("Отмена операции PayPal! ID:", id) 27 | } 28 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/17. HTTP методы/2. Обработка запросов только на определённом методе/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func handler(w http.ResponseWriter, r *http.Request) { 9 | if r.Method != http.MethodPatch { 10 | w.WriteHeader(http.StatusBadRequest) 11 | w.Write([]byte("Handler обрабатывает только метод PATCH! Переданный метод: " + r.Method)) 12 | return 13 | } 14 | 15 | fmt.Println("handler закончил своё выполнение.") 16 | } 17 | 18 | func main() { 19 | http.HandleFunc("/default", handler) 20 | 21 | fmt.Println("Запускаю HTTP сервер!") 22 | err := http.ListenAndServe(":9091", nil) 23 | if err != nil { 24 | fmt.Println("Ошибка во время работы HTTP сервера:", err) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/20. REST API. Теория и практика./1. Список дел/todo/task.go: -------------------------------------------------------------------------------- 1 | package todo 2 | 3 | import "time" 4 | 5 | type Task struct { 6 | Title string 7 | Description string 8 | Completed bool 9 | 10 | CreatedAt time.Time 11 | CompletedAt *time.Time 12 | } 13 | 14 | func NewTask(title string, description string) Task { 15 | return Task{ 16 | Title: title, 17 | Description: description, 18 | Completed: false, 19 | 20 | CreatedAt: time.Now(), 21 | CompletedAt: nil, 22 | } 23 | } 24 | 25 | func (t *Task) Complete() { 26 | completeTime := time.Now() 27 | 28 | t.Completed = true 29 | t.CompletedAt = &completeTime 30 | } 31 | 32 | func (t *Task) Uncomplete() { 33 | t.Completed = false 34 | t.CompletedAt = nil 35 | } 36 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/1. Интерфейсы/2. Модуль проведения оплат/payments/methods/crypto.go: -------------------------------------------------------------------------------- 1 | package methods 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | ) 7 | 8 | // Заглушка, иммитирующая проведение оплаты через крипто-кошелёк 9 | type Crypto struct{} 10 | 11 | func NewCrypto() Crypto { 12 | return Crypto{} 13 | } 14 | 15 | func (c Crypto) Pay(usd int) int { 16 | // Иммитируем проведения оплаты через крипто-кошелёк 17 | fmt.Println("Оплата криптовалютой!") 18 | fmt.Println("Размер оплаты:", usd, "USDT") 19 | 20 | // Генерируем и возвращаем рандомный ID оплаты 21 | return rand.Int() 22 | } 23 | 24 | func (c Crypto) Cancel(id int) { 25 | // Иммитируем отмену оплаты с переданным ID через крипто-кошелёк 26 | fmt.Println("Отмена крипто-операци! ID:", id) 27 | } 28 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/14. Тело HTTP запроса/1. Простое чтение тела HTTP запроса/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net/http" 7 | ) 8 | 9 | func handler(w http.ResponseWriter, r *http.Request) { 10 | httpRequestBody, err := io.ReadAll(r.Body) 11 | if err != nil { 12 | fmt.Println("failed to read HTTP body:", err) 13 | return 14 | } 15 | 16 | httpRequestBodyString := string(httpRequestBody) 17 | 18 | fmt.Println("Полученное тело входящего HTTP запроса:", httpRequestBodyString) 19 | } 20 | 21 | func main() { 22 | http.HandleFunc("/default", handler) 23 | 24 | fmt.Println("Запускаю HTTP сервер!") 25 | err := http.ListenAndServe(":9091", nil) 26 | if err != nil { 27 | fmt.Println("Ошибка во время работы HTTP сервера:", err) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/6. Конструкция select {}/1. Ожидание значений из двух каналов/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | intCh := make(chan int) 10 | strCh := make(chan string) 11 | 12 | // Через 200ms запишем в intCh значение 13 | go func() { 14 | time.Sleep(200 * time.Millisecond) 15 | intCh <- 1 16 | }() 17 | 18 | // Через 100ms запишем в strCh значение 19 | go func() { 20 | time.Sleep(100 * time.Millisecond) 21 | strCh <- "hi" 22 | }() 23 | 24 | // Блокируемя и ждём, когда в какой-то из каналов, intCh или strCh, придёт какое-то значение 25 | select { 26 | case number := <-intCh: 27 | fmt.Println("Получено число:", number) 28 | case str := <-strCh: 29 | fmt.Println("Получена строка:", str) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/20. REST API. Теория и практика./1. Список дел/http/dto.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "time" 7 | ) 8 | 9 | type CompleteTaskDTO struct { 10 | Complete bool 11 | } 12 | 13 | type TaskDTO struct { 14 | Title string 15 | Description string 16 | } 17 | 18 | func (t TaskDTO) ValidateForCreate() error { 19 | if t.Title == "" { 20 | return errors.New("title is empty") 21 | } 22 | 23 | if t.Description == "" { 24 | return errors.New("description is empty") 25 | } 26 | 27 | return nil 28 | } 29 | 30 | type ErrorDTO struct { 31 | Message string 32 | Time time.Time 33 | } 34 | 35 | func (e ErrorDTO) ToString() string { 36 | b, err := json.MarshalIndent(e, "", " ") 37 | if err != nil { 38 | panic(err) 39 | } 40 | 41 | return string(b) 42 | } 43 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/8. Структуры/1. Структура User без методов/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type User struct { 6 | Name string 7 | Age int 8 | PhoneNumber string 9 | IsClose bool 10 | Rating float64 11 | } 12 | 13 | func main() { 14 | user1 := User{ 15 | Name: "Иван", 16 | Age: 50, 17 | PhoneNumber: "+7 (911) 911 91-91", 18 | IsClose: true, 19 | Rating: 5.5, 20 | } 21 | 22 | user2 := User{ 23 | Name: "Пётр", 24 | Age: 60, 25 | PhoneNumber: "+7 (922) 922 92-92", 26 | // IsClose не указано => значение по умолчанию (false) 27 | // Rating не указано => значение по умолчанию (0.0) 28 | } 29 | 30 | fmt.Println("user1:", user1) 31 | fmt.Println("user1 Name:", user1.Name) 32 | 33 | fmt.Println("user2:", user2) 34 | fmt.Println("user2 Rating:", user2.Rating) 35 | } 36 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/4. Горутины и каналы/1. Один шахтёр/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | // Фукнция, описывающая поход в шахту 9 | // n -> номер похода в шахту 10 | func mine(n int) int { 11 | // Имитируем поход в шахту на одну секунду 12 | fmt.Println("Поход в шахту номер", n, "начался...") 13 | time.Sleep(1 * time.Second) 14 | fmt.Println("Поход в шахту номер", n, "закончился") 15 | 16 | // Возвращаем добытый уголь 17 | return 10 18 | } 19 | 20 | // main горутина 21 | func main() { 22 | coal := 0 23 | 24 | // Засекаем время 25 | initTime := time.Now() 26 | 27 | // Последовательно, раз за разом, ходим 3 раза в шахту 28 | coal += mine(1) 29 | coal += mine(2) 30 | coal += mine(3) 31 | 32 | // Итоговые значения угля и времени выполнения 33 | fmt.Println("Добыли", coal, "угля!") 34 | fmt.Println("Прошло времени:", time.Since(initTime)) 35 | } 36 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/10. Массивы Слайсы Мапы/3. Мапа/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | foo1() 7 | fmt.Println("-----------") 8 | foo2() 9 | } 10 | 11 | func foo1() { 12 | weather := map[int]int{ 13 | 10: +3, 14 | 11: -4, 15 | 12: +1, 16 | } 17 | 18 | weather[12] = -10 19 | weather[13] = +5 20 | 21 | for key, value := range weather { 22 | fmt.Println("key:", key, ", value:", value) 23 | } 24 | 25 | w11 := weather[11] 26 | fmt.Println("погода 11-го числа:", w11) 27 | } 28 | 29 | func foo2() { 30 | weather := make(map[int]int) 31 | 32 | weather[10] = -2 33 | weather[11] = -1 34 | weather[12] = 0 35 | 36 | w12, ok12 := weather[12] 37 | w13, ok13 := weather[13] 38 | 39 | fmt.Println("погода 12-го числа:", w12, ", является ли это записанным ранее значением, а не значением по-умолчанию:", ok12) 40 | fmt.Println("погода 13-го числа:", w13, ", является ли это записанным ранее значением, а не значением по-умолчанию:", ok13) 41 | } 42 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/13. Первый HTTP сервер/3. Спящий хендлер/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "time" 7 | ) 8 | 9 | func handler(w http.ResponseWriter, r *http.Request) { 10 | _, err := w.Write([]byte("Hello, World!")) 11 | if err != nil { 12 | fmt.Println("err:", err) 13 | return 14 | } 15 | 16 | fmt.Println("Handler отработал успешно!") 17 | } 18 | 19 | func sleepHandler(w http.ResponseWriter, r *http.Request) { 20 | time.Sleep(5 * time.Second) 21 | 22 | _, err := w.Write([]byte("HTTP response!")) 23 | if err != nil { 24 | fmt.Println("err:", err) 25 | return 26 | } 27 | 28 | fmt.Println("SleepHandler отработал успешно!") 29 | } 30 | 31 | func main() { 32 | http.HandleFunc("/", handler) 33 | http.HandleFunc("/sleep", sleepHandler) 34 | 35 | fmt.Println("Запускаю HTTP сервер!") 36 | err := http.ListenAndServe(":9091", nil) 37 | if err != nil { 38 | fmt.Println("Ошибка во время работы HTTP сервера:", err) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/6. Конструкция select {}/3. select + default/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | intCh := make(chan int) 10 | strCh := make(chan string) 11 | 12 | // Через 500ms запишем в intCh значение 13 | go func() { 14 | time.Sleep(500 * time.Millisecond) 15 | intCh <- 1 16 | }() 17 | 18 | // Через 250ms запишем в strCh значение 19 | go func() { 20 | time.Sleep(250 * time.Millisecond) 21 | strCh <- "hi" 22 | }() 23 | 24 | // Засыпаем на 100ms в main горутине 25 | time.Sleep(100 * time.Millisecond) 26 | 27 | // На момент достижения конструкции select у нас ещё ни одни канал не будет доступен для чтения. 28 | // Отработает секция default 29 | select { 30 | case number := <-intCh: 31 | fmt.Println("Получено число:", number) 32 | case str := <-strCh: 33 | fmt.Println("Получена строка:", str) 34 | default: 35 | fmt.Println("На момент наступления секции select не было доступно ни одного канала для чтения. Отработала секция default.") 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/4. Циклы/4. Flappy Bird продвинутая симуляция/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | // 🔋 11 | // 🐤 12 | // ❌ 13 | 14 | score := 0 15 | 16 | fmt.Println("Get Ready") 17 | fmt.Println("Счёт:", score) 18 | fmt.Println("") 19 | 20 | // Бесконечный цикл (аналог while true в других языках) 21 | for { 22 | fmt.Println("---------------------") 23 | fmt.Println("Я подлетаю к трубе!") 24 | fmt.Println("🐤 🔋🔋") 25 | fmt.Println("") 26 | 27 | fmt.Println("Я пролетаю через трубу!") 28 | fmt.Println("🔋🐤🔋") 29 | fmt.Println("") 30 | 31 | if rand.Intn(8) == 1 { 32 | fmt.Println("Я врезался в трубу :(") 33 | fmt.Println("🔋❌🔋") 34 | 35 | // прерывание цикла 36 | break 37 | } 38 | 39 | fmt.Println("Я пролетел через трубу!") 40 | fmt.Println("🔋🔋 🐤") 41 | fmt.Println("") 42 | 43 | score++ 44 | 45 | fmt.Println("Счёт:", score) 46 | fmt.Println("") 47 | 48 | time.Sleep(500 * time.Millisecond) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/1. Интерфейсы/2. Модуль проведения оплат/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "interfaces/payments" 5 | "interfaces/payments/methods" 6 | 7 | "github.com/k0kubun/pp" 8 | ) 9 | 10 | func main() { 11 | // Выбираем метод оплаты 12 | // method := methods.NewBank() // Оплата через банк 13 | // method := methods.NewPayPal() // Оплата через PayPal 14 | method := methods.NewCrypto() // Оплата через крипто-кошелёк 15 | 16 | // Создаём модуль проведения оплат 17 | paymentModule := payments.NewPaymentModule(method) 18 | 19 | // Проводим 3 оплаты 20 | paymentModule.Pay("Бургер", 5) 21 | phonePaymentID := paymentModule.Pay("Телефон", 500) 22 | paymentModule.Pay("Игра", 20) 23 | 24 | // По сохранённому ID оплаты за телефон, мы отменяем эту самую оплату 25 | paymentModule.Cancel(phonePaymentID) 26 | 27 | // Получаем информацию по всем проведённым оплатам 28 | allInfo := paymentModule.AllInfo() 29 | 30 | // Выводим эту информацию в консоль 31 | pp.Println("Информация по всем проведённым оплатам:", allInfo) 32 | } 33 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/10. Массивы Слайсы Мапы/2. Слайс/go.sum: -------------------------------------------------------------------------------- 1 | github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= 2 | github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= 3 | github.com/k0kubun/pp v3.0.1+incompatible h1:3tqvf7QgUnZ5tXO6pNAZlrvHgl6DvifjDrd9g2S9Z40= 4 | github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= 5 | github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= 6 | github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= 7 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 8 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 9 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 10 | golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= 11 | golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 12 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/9. Модули и пакеты/2. Модуль с пакетами/go.sum: -------------------------------------------------------------------------------- 1 | github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= 2 | github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= 3 | github.com/k0kubun/pp v3.0.1+incompatible h1:3tqvf7QgUnZ5tXO6pNAZlrvHgl6DvifjDrd9g2S9Z40= 4 | github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= 5 | github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= 6 | github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= 7 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 8 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 9 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 10 | golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= 11 | golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 12 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/1. Интерфейсы/2. Модуль проведения оплат/go.sum: -------------------------------------------------------------------------------- 1 | github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= 2 | github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= 3 | github.com/k0kubun/pp v3.0.1+incompatible h1:3tqvf7QgUnZ5tXO6pNAZlrvHgl6DvifjDrd9g2S9Z40= 4 | github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= 5 | github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= 6 | github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= 7 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 8 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 9 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 10 | golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= 11 | golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 12 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/9. Модули и пакеты/1. Простой модуль из одного main-пакета/go.sum: -------------------------------------------------------------------------------- 1 | github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= 2 | github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= 3 | github.com/k0kubun/pp v3.0.1+incompatible h1:3tqvf7QgUnZ5tXO6pNAZlrvHgl6DvifjDrd9g2S9Z40= 4 | github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= 5 | github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= 6 | github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= 7 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 8 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 9 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 10 | golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= 11 | golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 12 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/2. Обработка ошибок/1. Функция возвращает только ошибку/go.sum: -------------------------------------------------------------------------------- 1 | github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= 2 | github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= 3 | github.com/k0kubun/pp v3.0.1+incompatible h1:3tqvf7QgUnZ5tXO6pNAZlrvHgl6DvifjDrd9g2S9Z40= 4 | github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= 5 | github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= 6 | github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= 7 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 8 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 9 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 10 | golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= 11 | golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 12 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/2. Обработка ошибок/2. Функция возвращает значение и ошибку/go.sum: -------------------------------------------------------------------------------- 1 | github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= 2 | github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= 3 | github.com/k0kubun/pp v3.0.1+incompatible h1:3tqvf7QgUnZ5tXO6pNAZlrvHgl6DvifjDrd9g2S9Z40= 4 | github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= 5 | github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= 6 | github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= 7 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 8 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 9 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 10 | golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= 11 | golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 12 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/2. Обработка ошибок/2. Функция возвращает значение и ошибку/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "math/rand" 7 | 8 | "github.com/k0kubun/pp" 9 | ) 10 | 11 | type Car struct { 12 | Armor int 13 | } 14 | 15 | func (c *Car) Gas() (int, error) { 16 | // Проверили: есть ли ещё прочность у автомобиля, чтобы газануть? 17 | if c.Armor-10 <= 0 { 18 | // Если прочности нет, то мы не газуем, а возвращаем ошибку 19 | return 0, errors.New("Мы не стали газовать, чтобы не сломать машину!") 20 | } 21 | 22 | // Газуем, получаем случайное количество километров в час разгона, уменьшаем остаточную мощность автомобиля 23 | kmch := rand.Intn(150) 24 | c.Armor -= 10 25 | 26 | // Возвращаем новый разгон, ошибок нет 27 | return kmch, nil 28 | } 29 | 30 | func main() { 31 | car := Car{ 32 | Armor: 25, 33 | } 34 | 35 | for { 36 | pp.Println("Car до нажатия на газ:", car) 37 | kmch, err := car.Gas() 38 | pp.Println("Car после нажатия на газ:", car) 39 | if err != nil { 40 | fmt.Println("Ошибка нажатия на газ:", err) 41 | break 42 | } 43 | 44 | fmt.Println("Получившийся разгон:", kmch) 45 | fmt.Println("") 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/10. Гонка данных. Атомики. Мьютексы./2. Атомики/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "sync/atomic" 7 | ) 8 | 9 | // Глобалная переменная. Разделяемый между несколькими горутинами ресурс. 10 | var number atomic.Int64 11 | 12 | func increase(wg *sync.WaitGroup) { 13 | defer wg.Done() 14 | 15 | for i := 1; i <= 1000; i++ { 16 | // Регулируем конкуретный доступ к целочисленной переменной благодаря атомикам 17 | // Гонка данных отсутствует 18 | number.Add(1) 19 | } 20 | } 21 | 22 | func main() { 23 | // При помощи WaitGroup'ы дожидаемся окончательного выполнения 10-ти запущенных горутин 24 | wg := &sync.WaitGroup{} 25 | wg.Add(10) 26 | 27 | // Запускаем 10 горутин 28 | // Каждая 1.000 раз прибавляет 1 к number 29 | // Ожидается итоговое значение number == 10.000 30 | go increase(wg) 31 | go increase(wg) 32 | go increase(wg) 33 | go increase(wg) 34 | go increase(wg) 35 | 36 | go increase(wg) 37 | go increase(wg) 38 | go increase(wg) 39 | go increase(wg) 40 | go increase(wg) 41 | 42 | wg.Wait() 43 | 44 | // Гонки данных нет. number == 10.000 45 | fmt.Println("Итоговое значение переменной number:", number.Load()) 46 | } 47 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/10. Гонка данных. Атомики. Мьютексы./1. Гонка данных при увеличении целочисленной переменной/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | // Глобалная переменная. Разделяемый между несколькими горутинами ресурс. 9 | var number int = 0 10 | 11 | func increase(wg *sync.WaitGroup) { 12 | defer wg.Done() 13 | 14 | for i := 1; i <= 1000; i++ { 15 | // Нерегулируемый конкурентный доступ к разделяемому ресурсу 16 | // Как следствие -- гонка данных 17 | number++ 18 | } 19 | } 20 | 21 | func main() { 22 | // При помощи WaitGroup'ы дожидаемся окончательного выполнения 10-ти запущенных горутин 23 | wg := &sync.WaitGroup{} 24 | wg.Add(10) 25 | 26 | // Запускаем 10 горутин 27 | // Каждая 1.000 раз прибавляет 1 к number 28 | // Ожидается итоговое значение number == 10.000 29 | go increase(wg) 30 | go increase(wg) 31 | go increase(wg) 32 | go increase(wg) 33 | go increase(wg) 34 | 35 | go increase(wg) 36 | go increase(wg) 37 | go increase(wg) 38 | go increase(wg) 39 | go increase(wg) 40 | 41 | wg.Wait() 42 | 43 | // Из-за гонки данных мы потеряли много увеличений переменной number 44 | fmt.Println("Итоговое значение переменной number:", number) 45 | } 46 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/9. WaitGroup/1. Ожидание почтальонов/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | // Функция, описывающая почтальона, который 3 раза разносит указанную газету 10 | func postman(wg *sync.WaitGroup, text string) { 11 | // В конце функции postman мы явно укажем WaitGroup'е, что функция postman завершилась 12 | defer wg.Done() 13 | 14 | for i := 1; i <= 3; i++ { 15 | fmt.Println("Я почтальон, я отнёс газету", text, "в", i, "раз") 16 | time.Sleep(500 * time.Millisecond) 17 | } 18 | } 19 | 20 | func main() { 21 | // Создаём WaitGroup 22 | wg := &sync.WaitGroup{} 23 | 24 | // Указываем WaitGroup'е, что "сейчас я запущу одну горутину" 25 | wg.Add(1) 26 | // Запускаем горутину 27 | go postman(wg, "Новости") 28 | 29 | // Указываем WaitGroup'е, что "сейчас я запущу одну горутину" 30 | wg.Add(1) 31 | // Запускаем горутину 32 | go postman(wg, "Игровой журнал") 33 | 34 | // Указываем WaitGroup'е, что "сейчас я запущу одну горутину" 35 | wg.Add(1) 36 | // Запускаем горутину 37 | go postman(wg, "Автомобильная хроника") 38 | 39 | // Дожидаемся, пока все запущенные горутины завершатся 40 | wg.Wait() 41 | 42 | fmt.Println("main завершился!") 43 | } 44 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/10. Гонка данных. Атомики. Мьютексы./3. Гонка данных при добавлении новых элементов в слайс/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | // Глобалная переменная. Разделяемый между несколькими горутинами ресурс. 9 | var slice []int 10 | 11 | func addToSlice(wg *sync.WaitGroup) { 12 | defer wg.Done() 13 | 14 | for i := 1; i <= 1000; i++ { 15 | // Нерегулируемый конкурентный доступ к разделяемому ресурсу 16 | // Как следствие -- гонка данных 17 | slice = append(slice, i) 18 | } 19 | } 20 | 21 | func main() { 22 | // При помощи WaitGroup'ы дожидаемся окончательного выполнения 10-ти запущенных горутин 23 | wg := &sync.WaitGroup{} 24 | wg.Add(10) 25 | 26 | // Запускаем 10 горутин 27 | // Каждая 1.000 раз добавляет значение в слайс 28 | // Ожидается итоговый размер слайса == 10.000 29 | go addToSlice(wg) 30 | go addToSlice(wg) 31 | go addToSlice(wg) 32 | go addToSlice(wg) 33 | go addToSlice(wg) 34 | 35 | go addToSlice(wg) 36 | go addToSlice(wg) 37 | go addToSlice(wg) 38 | go addToSlice(wg) 39 | go addToSlice(wg) 40 | 41 | wg.Wait() 42 | 43 | // Из-за гонки данных мы потеряли много append'ов в слайс 44 | fmt.Println("Итоговый размер слайса:", len(slice)) 45 | } 46 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/10. Массивы Слайсы Мапы/1. Массив/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | intArr := [6]int{2, 4, 8, 16, 32, 64} 7 | 8 | fmt.Println("arr:", intArr) 9 | 10 | // вывод на экран первым видом for 11 | for i := 0; i < len(intArr); i++ { 12 | fmt.Println(i, "->", intArr[i]) 13 | } 14 | fmt.Println("---------------------") 15 | 16 | // умножаем каждый элемент на 2 первый раз первым видом for 17 | for i := 0; i < len(intArr); i++ { 18 | intArr[i] *= 2 19 | } 20 | 21 | // прибавляет каждому элементу, который больше 60, единицу вторым видом for 22 | for index, value := range intArr { 23 | if value > 60 { 24 | intArr[index] += 1 25 | 26 | // value++ не сработало бы 27 | // так как value это всего-лишь копия значения из массива 28 | } 29 | } 30 | 31 | // вывод на экран вторым видом for 32 | for index, value := range intArr { 33 | fmt.Println(index, "->", value) 34 | } 35 | fmt.Println("---------------------") 36 | 37 | // просто вывод всех индексов 38 | for index, _ := range intArr { 39 | fmt.Println("index:", index) 40 | } 41 | fmt.Println("---------------------") 42 | 43 | // просто вывод всех значений 44 | for _, value := range intArr { 45 | fmt.Println("value:", value) 46 | } 47 | fmt.Println("---------------------") 48 | } 49 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/2. Обработка ошибок/1. Функция возвращает только ошибку/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | 7 | "github.com/k0kubun/pp" 8 | ) 9 | 10 | type User struct { 11 | Name string 12 | Ballance int 13 | } 14 | 15 | func Pay(user *User, usd int) error { 16 | // Проверяем, хватает ли на балансе пользователя денег для совершения покупки 17 | if user.Ballance-usd < 0 { 18 | // Если не хватает, то возвращаем ошибку оплаты с сообщением "Недостаточно средств" 19 | return errors.New("Недостаточно средств!") 20 | } 21 | 22 | // Если хватает, то проводим оплату, списываем деньги 23 | user.Ballance -= usd 24 | 25 | // Ошибок не было => возвращаем nil (nil error == отсутствие ошибки) 26 | return nil 27 | } 28 | 29 | func main() { 30 | ballance := 100 31 | payment := 50 32 | 33 | /* 34 | - А если? 35 | 36 | ballance := 30 37 | payment := 50 38 | */ 39 | 40 | user := User{ 41 | Name: "Олег", 42 | Ballance: ballance, 43 | } 44 | 45 | pp.Println("User до проведения оплаты:", user) 46 | err := Pay(&user, payment) 47 | pp.Println("User после проведения оплаты:", user) 48 | 49 | if err != nil { 50 | fmt.Println("Оплаты не было! Причина:", err) 51 | } else { 52 | fmt.Println("Была произведена оплата! Ошибок не было.") 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/11. RWMutex/1. Ставим лайки/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | // Глобалная переменная. Разделяемый между несколькими горутинами ресурс. 10 | var likes int = 0 11 | 12 | // Мьютекст, позволяющий нам корректно регулировать конкуретный доступ к разделяемому ресурсу 13 | // Благодаря возможности отдельно брать блокировки на запись и отдельно брать блокировки на чтение 14 | // Имеем значительный прирост в производительности приложения, при условии ощутимой нагрузки на чтение 15 | var mtx sync.RWMutex 16 | 17 | func setLike(wg *sync.WaitGroup) { 18 | defer wg.Done() 19 | 20 | for i := 1; i <= 100_000; i++ { 21 | // Регулируем конкуретную запись в переменную likes 22 | mtx.Lock() 23 | likes++ 24 | mtx.Unlock() 25 | } 26 | } 27 | 28 | func getLike(wg *sync.WaitGroup) { 29 | defer wg.Done() 30 | 31 | for i := 1; i <= 100_000; i++ { 32 | // Регулируем конкуретное чтение из переменной likes 33 | mtx.RLock() 34 | _ = likes 35 | mtx.RUnlock() 36 | } 37 | } 38 | 39 | func main() { 40 | wg := &sync.WaitGroup{} 41 | 42 | initTime := time.Now() 43 | 44 | for i := 1; i <= 10; i++ { 45 | wg.Add(1) 46 | go setLike(wg) 47 | } 48 | 49 | for i := 1; i <= 10; i++ { 50 | wg.Add(1) 51 | go getLike(wg) 52 | } 53 | 54 | wg.Wait() 55 | 56 | fmt.Println("Время выполнения:", time.Since(initTime)) 57 | } 58 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/6. Конструкция select {}/2. Ожидание сообщений от двух друзей/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | type Message struct { 9 | Author string 10 | Text string 11 | } 12 | 13 | func main() { 14 | // Канал передачи сообщений от первого друга 15 | messageChan1 := make(chan Message) 16 | // Канал передачи сообщений от второго друга 17 | messageChan2 := make(chan Message) 18 | 19 | // В одной горутине запускаем первого "Друга", который нам раз в 3 секунды посылает сообщение 20 | go func() { 21 | for { 22 | messageChan1 <- Message{ 23 | Author: "Друг 1", 24 | Text: "Привет", 25 | } 26 | 27 | time.Sleep(3 * time.Second) 28 | } 29 | }() 30 | 31 | // Во второй горутине запускаем второго "Друга", который нам раз в 250 миллисекунд посылает сообщение 32 | go func() { 33 | for { 34 | messageChan2 <- Message{ 35 | Author: "Друг 2", 36 | Text: "Как дела?", 37 | } 38 | 39 | time.Sleep(250 * time.Millisecond) 40 | } 41 | }() 42 | 43 | // Бесконечное количество раз 44 | for { 45 | // Ожидаем сообщение от одного из каналов 46 | select { 47 | case msg1 := <-messageChan1: 48 | fmt.Println("Я получил сообщение от:", msg1.Author, "Текст сообщения:", msg1.Text) 49 | case msg2 := <-messageChan2: 50 | fmt.Println("Я получил сообщение от:", msg2.Author, "Текст сообщения:", msg2.Text) 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/10. Гонка данных. Атомики. Мьютексы./4. Мьютексы/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | // Глобалная переменная. Разделяемый между несколькими горутинами ресурс. 9 | var slice []int 10 | 11 | // Мьютекст, позволяющий нам корректно регулировать конкуретный доступ к разделяемому ресурсу 12 | var mtx sync.Mutex 13 | 14 | func addToSlice(wg *sync.WaitGroup) { 15 | defer wg.Done() 16 | 17 | for i := 1; i <= 1000; i++ { 18 | // Мьютекс -- своего рода "эстафетная палочка" 19 | // Благодаря мьютексту, в критической секции горутины выстраиваются в очередь 20 | // Как следствие -- отсутствие гонки данных 21 | mtx.Lock() 22 | slice = append(slice, i) 23 | mtx.Unlock() 24 | } 25 | } 26 | 27 | func main() { 28 | // При помощи WaitGroup'ы дожидаемся окончательного выполнения 10-ти запущенных горутин 29 | wg := &sync.WaitGroup{} 30 | wg.Add(10) 31 | 32 | // Запускаем 10 горутин 33 | // Каждая 1.000 раз добавляет значение в слайс 34 | // Ожидается итоговый размер слайса == 10.000 35 | go addToSlice(wg) 36 | go addToSlice(wg) 37 | go addToSlice(wg) 38 | go addToSlice(wg) 39 | go addToSlice(wg) 40 | 41 | go addToSlice(wg) 42 | go addToSlice(wg) 43 | go addToSlice(wg) 44 | go addToSlice(wg) 45 | go addToSlice(wg) 46 | 47 | wg.Wait() 48 | 49 | // Гонки данных нет, все 10.000 элементов будут успешно добавлены в слайс 50 | fmt.Println("Итоговый размер слайса:", len(slice)) 51 | } 52 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/13. Первый HTTP сервер/2. Несколько хендлеров/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func payHandler(w http.ResponseWriter, r *http.Request) { 9 | str := "Новый платёж обработан!" 10 | b := []byte(str) 11 | 12 | _, err := w.Write(b) 13 | if err != nil { 14 | fmt.Println("Во время записи HTTP ответа произошла ошибка:", err) 15 | } else { 16 | fmt.Println("Я корректно совершил оплату!") 17 | } 18 | } 19 | 20 | func cancelHandler(w http.ResponseWriter, r *http.Request) { 21 | str := "Оплата отменена!" 22 | b := []byte(str) 23 | 24 | _, err := w.Write(b) 25 | if err != nil { 26 | fmt.Println("Во время записи HTTP ответа произошла ошибка:", err) 27 | } else { 28 | fmt.Println("Я корректно отменил оплату!") 29 | } 30 | } 31 | 32 | func handler(w http.ResponseWriter, r *http.Request) { 33 | str := "Hello, World!" 34 | b := []byte(str) 35 | 36 | _, err := w.Write(b) 37 | if err != nil { 38 | fmt.Println("Во время записи HTTP ответа произошла ошибка:", err) 39 | } else { 40 | fmt.Println("Я корректно обработал HTTP запрос") 41 | } 42 | } 43 | 44 | func main() { 45 | http.HandleFunc("/default", handler) 46 | http.HandleFunc("/pay", payHandler) 47 | http.HandleFunc("/cancel", cancelHandler) 48 | 49 | fmt.Println("Запускаю HTTP сервер!") 50 | err := http.ListenAndServe(":9091", nil) 51 | if err != nil { 52 | fmt.Println("Ошибка во время работы HTTP сервера:", err) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/4. Горутины и каналы/2. Несколько шахтёров/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | // Фукнция, описывающая поход в шахту 9 | // transferPoint -> канал для передачи целочисленных значений между горутинами 10 | // n -> номер запущенной горутины 11 | func mine(transferPoint chan int, n int) { 12 | // Имитируем поход в шахту на одну секунду 13 | fmt.Println("Поход в шахту номер", n, "начался...") 14 | time.Sleep(1 * time.Second) 15 | fmt.Println("Поход в шахту номер", n, "закончился") 16 | 17 | // Идём в пункт передачи угля 18 | // Если канал НЕ буферизированный, то будм тут блокироваться и ждать, пока кто-то из другой горутины примет передаваемое значение 19 | transferPoint <- 10 20 | 21 | // Сигнализируем о том, что значение было фактически передано через канал между двуми разными горутинами 22 | fmt.Println("Поход в шахту номер", n, "уголь успешно передан!") 23 | } 24 | 25 | // main горутина 26 | func main() { 27 | coal := 0 28 | transferPoint := make(chan int) 29 | 30 | // Засекаем время 31 | initTime := time.Now() 32 | 33 | // Запускаем трёх шахтёров (запускаем 3 горутины) 34 | go mine(transferPoint, 1) 35 | go mine(transferPoint, 2) 36 | go mine(transferPoint, 3) 37 | 38 | // 3 раза приходим в пункт передачи угля за углём (3 раза читаем из канала) 39 | coal += <-transferPoint 40 | coal += <-transferPoint 41 | coal += <-transferPoint 42 | 43 | // Итоговые значения угля и времени выполнения 44 | fmt.Println("Добыли", coal, "угля!") 45 | fmt.Println("Прошло времени:", time.Since(initTime)) 46 | } 47 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/20. REST API. Теория и практика./1. Список дел/http/server.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "errors" 5 | "net/http" 6 | 7 | "github.com/gorilla/mux" 8 | ) 9 | 10 | type HTTPServer struct { 11 | httpHandlers *HTTPHandlers 12 | } 13 | 14 | func NewHTTPServer(httpHandler *HTTPHandlers) *HTTPServer { 15 | return &HTTPServer{ 16 | httpHandlers: httpHandler, 17 | } 18 | } 19 | 20 | func (s *HTTPServer) StartServer() error { 21 | router := mux.NewRouter() 22 | 23 | router.Path("/tasks").Methods("POST").HandlerFunc(s.httpHandlers.HandleCreateTask) 24 | router.Path("/tasks/{title}").Methods("GET").HandlerFunc(s.httpHandlers.HandleGetTask) 25 | 26 | // ребята, тут я зафакапил, конечно же, если мы получаем список НЕвыполненных задач, то в query параметре должно быть completed=false, а не true 27 | // потому что completed=true обозначает "список всех выполненных задач", а мы хотим наоборот 28 | // ("completed", "false") 29 | // ⤵️⤵️⤵️ ⤵️⤵️⤵️ 30 | router.Path("/tasks").Methods("GET").Queries("completed", "true").HandlerFunc(s.httpHandlers.HandleGetAllUncompletedTasks) 31 | 32 | router.Path("/tasks").Methods("GET").HandlerFunc(s.httpHandlers.HandleGetAllTasks) 33 | router.Path("/tasks/{title}").Methods("PATCH").HandlerFunc(s.httpHandlers.HandleCompleteTask) 34 | router.Path("/tasks/{title}").Methods("DELETE").HandlerFunc(s.httpHandlers.HandleDeleteTask) 35 | 36 | if err := http.ListenAndServe(":9091", router); err != nil { 37 | if errors.Is(err, http.ErrServerClosed) { 38 | return nil 39 | } 40 | 41 | return err 42 | } 43 | 44 | return nil 45 | } 46 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/14. Тело HTTP запроса/2. Управление финансами/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net/http" 7 | "strconv" 8 | "sync" 9 | ) 10 | 11 | var mtx = sync.Mutex{} 12 | var money = 1000 // usd 13 | var bank = 0 // usd 14 | 15 | func payHandler(w http.ResponseWriter, r *http.Request) { 16 | httpRequestBody, err := io.ReadAll(r.Body) 17 | if err != nil { 18 | fmt.Println("failed to read HTTP body:", err) 19 | return 20 | } 21 | 22 | httpRequestBodyString := string(httpRequestBody) 23 | 24 | paymentAmount, err := strconv.Atoi(httpRequestBodyString) 25 | if err != nil { 26 | fmt.Println("failed to convert HTTP body to integer:", err) 27 | return 28 | } 29 | 30 | mtx.Lock() 31 | if money-paymentAmount >= 0 { 32 | money -= paymentAmount 33 | fmt.Println("Оплата прошла успешно:", money) 34 | } 35 | mtx.Unlock() 36 | } 37 | 38 | func saveHandler(w http.ResponseWriter, r *http.Request) { 39 | httpRequestBody, err := io.ReadAll(r.Body) 40 | if err != nil { 41 | fmt.Println("failed to read HTTP request body:", err) 42 | return 43 | } 44 | 45 | httpRequestBodyString := string(httpRequestBody) 46 | 47 | saveAmount, err := strconv.Atoi(httpRequestBodyString) 48 | if err != nil { 49 | fmt.Println("failed to convert string to integer:", err) 50 | return 51 | } 52 | 53 | mtx.Lock() 54 | if saveAmount <= money { 55 | bank += saveAmount 56 | money -= saveAmount 57 | fmt.Println("Денег в копилке:", bank) 58 | fmt.Println("Балланс кошелька:", money) 59 | } 60 | mtx.Unlock() 61 | } 62 | 63 | func main() { 64 | http.HandleFunc("/pay", payHandler) 65 | http.HandleFunc("/save", saveHandler) 66 | 67 | fmt.Println("Запускаю HTTP сервер!") 68 | err := http.ListenAndServe(":9091", nil) 69 | if err != nil { 70 | fmt.Println("Ошибка во время работы HTTP сервера:", err) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/7. Закрытие каналов. Аксиомы каналов./5. Осмысленное закрытие канала/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | // Создали пункт передачи угля. Сразу после создания канал всегда открыт. 11 | transferPoint := make(chan int) 12 | 13 | go func() { 14 | // Получаем случайное число: либо 3 либо 4 либо 5 либо 6 15 | iterations := 3 + rand.Intn(4) 16 | fmt.Println("Количество найденного угля:", iterations) 17 | 18 | // Добываем весь случайно найденный уголь 19 | for i := 1; i <= iterations; i++ { 20 | // Иммитируем 300ms добычу очередной залежи угля 21 | time.Sleep(300 * time.Millisecond) 22 | 23 | // Передаём найденный уголь 24 | transferPoint <- 10 25 | } 26 | 27 | // Закрываем канал, благодаря чему сигнализируем читающим из этого канала горутинам, что новых осмысленных значений больше не будет в этом канале 28 | close(transferPoint) 29 | }() 30 | 31 | // Склад угля 32 | coal := 0 33 | 34 | for { 35 | // Ждём уголь в пункте передачи угля 36 | v, ok := <-transferPoint 37 | // Если переданное значение -- значение по умолчанию, значит канал закрыт 38 | // А если канал закрыт, значит запись в этот канал закончена 39 | // Если запись в этот канал закончена, значит нет смысла продолжать читать канал 40 | if !ok { 41 | fmt.Println("Шахтёр обработал всю шахту и добыл весь найденный там уголь!") 42 | break 43 | } 44 | 45 | // Если ok == true, значит v -- осмысленное переданное другой горутиной значение 46 | // Добавляем полученный уголь в склад угля 47 | coal += v 48 | 49 | // Выводим на каждой итерации значение переменной coal 50 | fmt.Println("coal:", coal) 51 | } 52 | 53 | /* 54 | // Тоже самое, что и в предыдущем цикле for, просто более красиво 55 | for v := range transferPoint { 56 | coal += v 57 | fmt.Println("coal:", coal) 58 | } 59 | 60 | fmt.Println("Шахтёр обработал всю шахту и добыл весь найденный там уголь!") 61 | */ 62 | 63 | fmt.Println("Суммарно добытый уголь:", coal) 64 | } 65 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/8. Контекст/1. Контроль выполнения разных групп горутин/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | func Foo(ctx context.Context, n int) { 10 | for { 11 | select { 12 | case <-ctx.Done(): 13 | fmt.Println("Foo завершилась :(", n) 14 | return 15 | default: 16 | fmt.Println("Foo продолжает своё выполнение!", n) 17 | } 18 | 19 | time.Sleep(100 * time.Millisecond) 20 | } 21 | } 22 | 23 | func Boo(ctx context.Context, n int) { 24 | for { 25 | select { 26 | case <-ctx.Done(): 27 | fmt.Println("Boo завершилась :(", n) 28 | return 29 | default: 30 | fmt.Println("Boo продолжает своё выполнение!", n) 31 | } 32 | 33 | time.Sleep(100 * time.Millisecond) 34 | } 35 | } 36 | 37 | func main() { 38 | // создаём родительский контекст 39 | parentContext, parentCancel := context.WithCancel(context.Background()) 40 | // наследуем от родительского контекста дочерний контекст 41 | childContext, childCancel := context.WithCancel(parentContext) 42 | 43 | // запускаем 3 горутины с родительским контекстом 44 | go Foo(parentContext, 1) 45 | go Foo(parentContext, 2) 46 | go Foo(parentContext, 3) 47 | 48 | // запускаем 3 горутины с дочерним контекстом 49 | go Boo(childContext, 1) 50 | go Boo(childContext, 2) 51 | go Boo(childContext, 3) 52 | 53 | // через 2 секунды отменяем дочерний контекст 54 | // тем самым завершая все горутины, которые зависят от дочернего контекста 55 | time.Sleep(2 * time.Second) 56 | childCancel() 57 | 58 | // через ещё 2 секунды завершаем родительский конткст 59 | // завершая все горутины, которые зависят от родительского контекста 60 | // а так же автоматически завершается дочерний контекст, если он ещё не был отменён 61 | time.Sleep(2 * time.Second) 62 | parentCancel() 63 | 64 | // ещё одну секунду спим в main горутине, чтобы продемонстрировать 65 | // что Foo и Boo горутины завершились именно при помощи контекста 66 | // а просто вместе со всей программой 67 | time.Sleep(1 * time.Second) 68 | fmt.Println("main завершился!") 69 | } 70 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/12. Concurrency большой пример/1. Пример/postman/postman.go: -------------------------------------------------------------------------------- 1 | package postman 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "sync" 7 | "time" 8 | ) 9 | 10 | // Функция, описывающая работу одного отдельного почтальона 11 | func Postman(ctx context.Context, wg *sync.WaitGroup, transferPoint chan<- string, n int, mail string) { 12 | defer wg.Done() 13 | 14 | for { 15 | // Этот почтально завершит своё выполнение, только после того 16 | // Как увидит сигнал о завершении рабочего дня через ctx 17 | // И доработает свою последнюю рабочую итерацию 18 | select { 19 | case <-ctx.Done(): 20 | fmt.Println("Я почтальон номер:", n, "Мой рабочий день закончен!") 21 | return 22 | default: 23 | fmt.Println("Я почтальон номер:", n, "Взял письмо") 24 | time.Sleep(1 * time.Second) 25 | fmt.Println("Я почтальон номер:", n, "Донёс письмо до почты:", mail) 26 | 27 | transferPoint <- mail 28 | 29 | fmt.Println("Я почтальон номер:", n, "Передал письмо:", mail) 30 | } 31 | } 32 | } 33 | 34 | // PostmanPool -- функция, запускающая postmanCount почтальонов, 35 | // Позволяющая потребителям PostmanPool функции получать письма от запущенных почтальонов 36 | // И контролирующая закрытие канала общения 37 | func PostmanPool(ctx context.Context, postmanCount int) <-chan string { 38 | mailTransferPoint := make(chan string) 39 | 40 | wg := &sync.WaitGroup{} 41 | 42 | for i := 1; i <= postmanCount; i++ { 43 | wg.Add(1) 44 | go Postman(ctx, wg, mailTransferPoint, i, postmanToMail(i)) 45 | } 46 | 47 | go func() { 48 | wg.Wait() 49 | close(mailTransferPoint) 50 | }() 51 | 52 | return mailTransferPoint 53 | } 54 | 55 | // Заготовка конкретных писем для конкретных почтальонов 56 | // Если для какого-то почтальона нет заготовленного письма -- этот почтальон разносит лотерею 57 | func postmanToMail(postmanNumber int) string { 58 | ptm := map[int]string{ 59 | 1: "Семейный привет", 60 | 2: "Приглашение от друга", 61 | 3: "Информация из автосервиса", 62 | } 63 | 64 | mail, ok := ptm[postmanNumber] 65 | if !ok { 66 | return "Лотерея" 67 | } 68 | 69 | return mail 70 | } 71 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/18. JSON/1. Приём и передача комплексной информации по HTTP/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | "sync" 8 | "time" 9 | ) 10 | 11 | type Payment struct { 12 | // Описание покупки 13 | Description string `json:"description"` 14 | 15 | // Сумма покупки 16 | USD int `json:"usd"` 17 | 18 | // ФИО человека, совершающего покупку 19 | FullName string `json:"fullName"` 20 | 21 | // Место прописки человека, совершающего покупку 22 | Address string `json:"address"` 23 | 24 | // Время проведения оплаты 25 | Time time.Time 26 | } 27 | 28 | func (p Payment) Println() { 29 | fmt.Println("Description:", p.Description) 30 | fmt.Println("USD:", p.USD) 31 | fmt.Println("FullName:", p.FullName) 32 | fmt.Println("Address:", p.Address) 33 | } 34 | 35 | var mtx = sync.Mutex{} 36 | var money = 1000 37 | var paymentHistory = make([]Payment, 0) 38 | 39 | type HttpResponse struct { 40 | Money int `json:"mmmoney"` 41 | PaymentHistory []Payment `json:"phistory"` 42 | } 43 | 44 | func payHandler(w http.ResponseWriter, r *http.Request) { 45 | var payment Payment 46 | if err := json.NewDecoder(r.Body).Decode(&payment); err != nil { 47 | fmt.Println("err:", err) 48 | w.WriteHeader(http.StatusInternalServerError) 49 | return 50 | } 51 | payment.Time = time.Now() 52 | 53 | payment.Println() 54 | 55 | mtx.Lock() 56 | if money-payment.USD >= 0 { 57 | money -= payment.USD 58 | } 59 | 60 | paymentHistory = append(paymentHistory, payment) 61 | 62 | httpResponse := HttpResponse{ 63 | Money: money, 64 | PaymentHistory: paymentHistory, 65 | } 66 | 67 | b, err := json.Marshal(httpResponse) 68 | if err != nil { 69 | fmt.Println("err:", err) 70 | w.WriteHeader(http.StatusInternalServerError) 71 | return 72 | } 73 | 74 | if _, err := w.Write(b); err != nil { 75 | fmt.Println("err:", err) 76 | return 77 | } 78 | 79 | mtx.Unlock() 80 | } 81 | 82 | func main() { 83 | http.HandleFunc("/pay", payHandler) 84 | 85 | if err := http.ListenAndServe(":9091", nil); err != nil { 86 | fmt.Println("Ошибка во время работы HTTP сервера:", err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/11. Пользовательский ввод/1. Чтение пользовательского ввода/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | // Введите команду: добавить лук 11 | // вы хотите добавить лук 12 | 13 | // Введите команду: удалить морковь 14 | // вы кажется хотите удалить морковь 15 | 16 | // неивестная команда 17 | // | 18 | // help 19 | // вот список команд! 20 | 21 | // выйти 22 | 23 | func main() { 24 | scanner := bufio.NewScanner(os.Stdin) 25 | 26 | for { 27 | fmt.Print("Введите команду: ") 28 | 29 | if ok := scanner.Scan(); !ok { 30 | fmt.Println("Ошибка ввода!") 31 | return 32 | } 33 | 34 | text := scanner.Text() 35 | 36 | fields := strings.Fields(text) 37 | 38 | if len(fields) == 0 { 39 | fmt.Println("Вы ничего не ввели!") 40 | return 41 | } 42 | 43 | cmd := fields[0] 44 | 45 | if cmd == "выйти" { 46 | fmt.Println("До скорого!") 47 | return 48 | } 49 | 50 | if cmd == "добавить" { 51 | str := "" 52 | for i := 1; i < len(fields); i++ { 53 | str += fields[i] 54 | 55 | if i != len(fields)-1 { 56 | str += " " 57 | } 58 | } 59 | 60 | fmt.Println("вы хотите добавить:", str) 61 | fmt.Println("") 62 | } else if cmd == "удалить" { 63 | str := "" 64 | for i := 1; i < len(fields); i++ { 65 | str += fields[i] 66 | 67 | if i != len(fields)-1 { 68 | str += " " 69 | } 70 | } 71 | 72 | fmt.Println("вы кажется хотите удалить:", str) 73 | fmt.Println("") 74 | } else if cmd == "help" { 75 | fmt.Println("Команда: help") 76 | fmt.Println("-- эта команда выводит список доступных команд") 77 | fmt.Println("") 78 | fmt.Println("Команда: добавить {что нужно добавить}") 79 | fmt.Println("-- эта команда позволяет добавлять что-то") 80 | fmt.Println("") 81 | fmt.Println("Команда: удалить {что нужно удалить}") 82 | fmt.Println("-- эта команда позволяет удалять что-то") 83 | fmt.Println("") 84 | fmt.Println("Команда: выйти") 85 | fmt.Println("-- эта команда позволяет завершить программу") 86 | fmt.Println("") 87 | } else { 88 | fmt.Println("Вы ввели неизвестную команду") 89 | fmt.Println("") 90 | } 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/10. Массивы Слайсы Мапы/2. Слайс/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/k0kubun/pp" 7 | ) 8 | 9 | type User struct { 10 | Name string 11 | Rating float64 12 | Premium bool 13 | } 14 | 15 | func main() { 16 | foo1() 17 | fmt.Println("<<<<<<<>>>>>>>") 18 | foo2() 19 | fmt.Println("<<<<<<<>>>>>>>") 20 | foo3() 21 | } 22 | 23 | func foo1() { 24 | slice1 := []User{ 25 | User{ 26 | Name: "Иван", 27 | Rating: 5.5, 28 | Premium: true, 29 | }, 30 | User{ 31 | Name: "Сергей", 32 | Rating: 4.5, 33 | Premium: false, 34 | }, 35 | User{ 36 | Name: "Данил", 37 | Rating: 7.5, 38 | Premium: true, 39 | }, 40 | } 41 | 42 | pp.Println("slice1 до:", slice1) 43 | fmt.Println("---------------") 44 | 45 | // можем динамически добавлять элементы 46 | slice1 = append( 47 | slice1, User{ 48 | Name: "Олег", 49 | Rating: 8.2, 50 | Premium: false, 51 | }, 52 | ) 53 | slice1 = append( 54 | slice1, User{ 55 | Name: "Пётр", 56 | Rating: 3.1, 57 | Premium: true, 58 | }, 59 | ) 60 | 61 | pp.Println("slice1 после:", slice1) 62 | fmt.Println("---------------") 63 | } 64 | 65 | func foo2() { 66 | slice2 := make([]User, 5) 67 | pp.Println("slice2:", slice2) 68 | } 69 | 70 | func foo3() { 71 | // можем заранее предвыделить память 72 | // если знаем кол-во элементов 73 | // make([]User, 0, 3) 74 | slice3 := make([]User, 0) 75 | 76 | slice3 = append(slice3, User{ 77 | Name: "Иван", 78 | Rating: 5.5, 79 | Premium: true, 80 | }) 81 | 82 | slice3 = append(slice3, 83 | User{ 84 | Name: "Сергей", 85 | Rating: 4.5, 86 | Premium: false, 87 | }, 88 | User{ 89 | Name: "Данил", 90 | Rating: 7.5, 91 | Premium: true, 92 | }, 93 | ) 94 | 95 | pp.Println("slice3 до:", slice3) 96 | fmt.Println("---------------") 97 | 98 | // каждому у кого Premium аккаун добавляет 1.0 соц рейтинга 99 | for index, user := range slice3 { 100 | if user.Premium { 101 | slice3[index].Rating += 1.0 102 | } 103 | } 104 | 105 | pp.Println("slice3 после:", slice3) 106 | fmt.Println("---------------") 107 | } 108 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/12. Concurrency большой пример/1. Пример/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "concurrency/miner" 5 | "concurrency/postman" 6 | "context" 7 | "fmt" 8 | "sync" 9 | "sync/atomic" 10 | "time" 11 | ) 12 | 13 | func main() { 14 | // Хранилище угля 15 | var coal atomic.Int64 16 | 17 | // Хранилище писем 18 | mtx := sync.Mutex{} 19 | var mails []string 20 | 21 | // Создаём отдельные контексты для шахтёров и почтальонов 22 | // Для возможности отдельно завершать шахтёров и отдельно завершать почтальонов 23 | minerContext, minerCancel := context.WithCancel(context.Background()) 24 | postmanContext, postmanCancel := context.WithCancel(context.Background()) 25 | 26 | // Через 3 секунды мы завершим рабочий день шахтёров 27 | go func() { 28 | time.Sleep(3 * time.Second) 29 | fmt.Println("--->>> Рабочий день шахтёров окончен!") 30 | minerCancel() 31 | }() 32 | 33 | // Через 6 секунд мы завершим рабочий день почтальонов 34 | go func() { 35 | time.Sleep(6 * time.Second) 36 | fmt.Println("--->>> Рабочий день почтальоном окончен!") 37 | postmanCancel() 38 | }() 39 | 40 | // Запускаем 2-х шахтёров, получаем пункт передачи угля 41 | coalTransferPoint := miner.MinerPool(minerContext, 2) 42 | // Запускаем 2-х почтальонов, получаем пункт передачи писем 43 | mailTransferPoint := postman.PostmanPool(postmanContext, 2) 44 | 45 | // Засекаем время выполнения всей работы 46 | initTime := time.Now() 47 | 48 | wg := &sync.WaitGroup{} 49 | 50 | // В отдельной горутине вычитываем входящий уголь 51 | wg.Add(1) 52 | go func() { 53 | defer wg.Done() 54 | 55 | for v := range coalTransferPoint { 56 | coal.Add(int64(v)) 57 | time.Sleep(1 * time.Second) 58 | } 59 | }() 60 | 61 | // В отдельной горутине вычитываем входящие письма 62 | wg.Add(1) 63 | go func() { 64 | defer wg.Done() 65 | 66 | for v := range mailTransferPoint { 67 | mtx.Lock() 68 | mails = append(mails, v) 69 | mtx.Unlock() 70 | 71 | time.Sleep(1 * time.Second) 72 | } 73 | }() 74 | 75 | wg.Wait() 76 | 77 | // Далее выводим результирующие значения 78 | 79 | fmt.Println("Суммарно добытый уголь:", coal.Load()) 80 | 81 | mtx.Lock() 82 | fmt.Println("Суммарное количество полученных писем:", len(mails)) 83 | mtx.Unlock() 84 | 85 | fmt.Println("Затраченное время:", time.Since(initTime)) 86 | } 87 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/20. REST API. Теория и практика./1. Список дел/todo/list.go: -------------------------------------------------------------------------------- 1 | package todo 2 | 3 | import "sync" 4 | 5 | type List struct { 6 | tasks map[string]Task 7 | mtx sync.RWMutex 8 | } 9 | 10 | func NewList() *List { 11 | return &List{ 12 | tasks: make(map[string]Task), 13 | } 14 | } 15 | 16 | func (l *List) AddTask(task Task) error { 17 | l.mtx.Lock() 18 | defer l.mtx.Unlock() 19 | 20 | if _, ok := l.tasks[task.Title]; ok { 21 | return ErrTaskAlreadyExists 22 | } 23 | 24 | l.tasks[task.Title] = task 25 | 26 | return nil 27 | } 28 | 29 | func (l *List) GetTask(title string) (Task, error) { 30 | l.mtx.RLock() 31 | defer l.mtx.RUnlock() 32 | 33 | task, ok := l.tasks[title] 34 | if !ok { 35 | return Task{}, ErrTaskNotFound 36 | } 37 | 38 | return task, nil 39 | } 40 | 41 | func (l *List) ListTasks() map[string]Task { 42 | l.mtx.RLock() 43 | defer l.mtx.RUnlock() 44 | 45 | tmp := make(map[string]Task, len(l.tasks)) 46 | 47 | for k, v := range l.tasks { 48 | tmp[k] = v 49 | } 50 | 51 | return tmp 52 | } 53 | 54 | func (l *List) ListUncompletedTasks() map[string]Task { 55 | l.mtx.RLock() 56 | defer l.mtx.RUnlock() 57 | 58 | uncompletedTasks := make(map[string]Task) 59 | 60 | for title, task := range l.tasks { 61 | if !task.Completed { 62 | uncompletedTasks[title] = task 63 | } 64 | } 65 | 66 | return uncompletedTasks 67 | } 68 | 69 | func (l *List) CompleteTask(title string) (Task, error) { 70 | l.mtx.Lock() 71 | defer l.mtx.Unlock() 72 | 73 | task, ok := l.tasks[title] 74 | if !ok { 75 | return Task{}, ErrTaskNotFound 76 | } 77 | 78 | task.Complete() 79 | 80 | l.tasks[title] = task 81 | 82 | return task, nil 83 | } 84 | 85 | func (l *List) UncompleteTask(title string) (Task, error) { 86 | l.mtx.Lock() 87 | defer l.mtx.Unlock() 88 | 89 | task, ok := l.tasks[title] 90 | if !ok { 91 | return Task{}, ErrTaskNotFound 92 | } 93 | 94 | task.Uncomplete() 95 | 96 | l.tasks[title] = task 97 | 98 | return task, nil 99 | } 100 | 101 | func (l *List) DeleteTask(title string) error { 102 | l.mtx.Lock() 103 | defer l.mtx.Unlock() 104 | 105 | _, ok := l.tasks[title] 106 | if !ok { 107 | return ErrTaskNotFound 108 | } 109 | 110 | delete(l.tasks, title) 111 | 112 | return nil 113 | } 114 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/1. Интерфейсы/1. Простой пример. Интерфейс Auto./main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Интерфейс Auto 6 | // Каждая структура, у которой есть методы: 7 | // - StepOnGas() 8 | // - StepOnBrake() 9 | // Автоматически удовлетворяет интерфейсу Auto и может быть использована на его месте 10 | type Auto interface { 11 | StepOnGas() 12 | StepOnBrake() 13 | } 14 | 15 | // Структура BMW 16 | // Имеет: 17 | // - Метод StepOnGas() 18 | // - Метод StepOnBrake() 19 | // - Метод BipBip() 20 | // Вывод: 21 | // - Наличие методов StepOnGas() + StepOnBrake() говорит о том, что BMW подходит под интерфейс Auto 22 | // - Наличие метода BipBip() не мешает структуре BMW удовлетворять интерфейсу Auto 23 | type BMW struct{} 24 | 25 | func (b BMW) StepOnGas() { 26 | fmt.Println("Я БМВ! 550 лошадинных сил! Жмём на газ!") 27 | } 28 | 29 | func (b BMW) StepOnBrake() { 30 | fmt.Println("Я БМВ! Тормоз в пол! Хорошее торможение!") 31 | } 32 | 33 | func (b BMW) BipBip() { 34 | fmt.Println("Я БМВ! Я нажимаю клаксон!") 35 | } 36 | 37 | // Структура Zhiga 38 | // Имеет: 39 | // - Метод StepOnGas() 40 | // - Метод StepOnBrake() 41 | // Вывод: 42 | // - Наличие методов StepOnGas() + StepOnBrake() говорит о том, что Zhiga подходит под интерфейс Auto 43 | type Zhiga struct{} 44 | 45 | func (z Zhiga) StepOnGas() { 46 | fmt.Println("Я жига! 2107! Пробую не развалиться!") 47 | } 48 | 49 | func (z Zhiga) StepOnBrake() { 50 | fmt.Println("Я жига! Вот блин тормоза чуть не отвалились(") 51 | } 52 | 53 | // Структура Lambo 54 | // Имеет: 55 | // - Метод StepOnGas() 56 | // Вывод: 57 | // - Отсутствие метода StepOnBreak() не позволяет структуре Lambo удовлетворять интерфейсу Auto 58 | type Lambo struct{} 59 | 60 | func (l Lambo) StepOnGas() { 61 | fmt.Println("Я ламба! 1500 лс! Еду быстро!") 62 | } 63 | 64 | // Функция ride(auto Auto) 65 | // Принимает: 66 | // - interface Auto 67 | // Вывод: 68 | // - Функция ride(auto Auto) может принимать любую структуру, которая подходит под интерфейс Auto 69 | func ride(auto Auto) { 70 | fmt.Println("Я водитель!") 71 | fmt.Println("Я сажусь в свою машину!") 72 | fmt.Println("И нажимаю на газ...") 73 | auto.StepOnGas() 74 | auto.StepOnBrake() 75 | } 76 | 77 | func main() { 78 | /* 79 | bmw := BMW{} 80 | zhiga := Zhiga{} 81 | lambo := Lambo{} 82 | 83 | ride(bmw) // ok 84 | ride(zhiga) // ok 85 | ride(lambo) // ошибка: в структуре Lambo отсутсвует необходимый метод StepOnBrake(), Lambo не является Auto 86 | */ 87 | } 88 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/12. Concurrency большой пример/1. Пример/miner/miner.go: -------------------------------------------------------------------------------- 1 | package miner 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "sync" 7 | "time" 8 | ) 9 | 10 | // Функция, описывающая работу одного отдельного шахтёра 11 | func Miner( 12 | ctx context.Context, 13 | wg *sync.WaitGroup, 14 | transferPoint chan<- int, 15 | n int, 16 | power int, 17 | ) { 18 | defer wg.Done() 19 | 20 | for { 21 | // Этот шахтёр завершит своё выполнение, только после того 22 | // Как увидит сигнал о завершении рабочего дня через ctx 23 | // И доработает свою последнюю рабочую итерацию 24 | select { 25 | case <-ctx.Done(): 26 | fmt.Println("Я шахтёр номер:", n, "Мой рабочий день закончен!") 27 | return 28 | default: 29 | fmt.Println("Я шахтёр номер:", n, "Начал добывать уголь!") 30 | time.Sleep(1 * time.Second) 31 | fmt.Println("Я шахтёр номер:", n, "Добыл уголь:", power) 32 | 33 | transferPoint <- power 34 | fmt.Println("Я шахтёр номер:", n, "Передал уголь:", power) 35 | } 36 | } 37 | } 38 | 39 | /* 40 | func Miner( 41 | ctx context.Context, 42 | wg *sync.WaitGroup, 43 | transferPoint chan<- int, 44 | n int, 45 | power int, 46 | ) { 47 | defer wg.Done() 48 | 49 | for { 50 | // Этот шахтёр завершит своё выполнение СРАЗУ после сигнала о завершении рабочего дня 51 | fmt.Println("Я шахтёр номер:", n, "Начал добывать уголь!") 52 | 53 | select { 54 | case <-ctx.Done(): 55 | fmt.Println("Я шахтёр номер:", n, "Мой рабочий день закончен!") 56 | return 57 | case <-time.After(1 * time.Second): 58 | fmt.Println("Я шахтёр номер:", n, "Добыл уголь:", power) 59 | } 60 | 61 | select { 62 | case <-ctx.Done(): 63 | fmt.Println("Я шахтёр номер:", n, "Мой рабочий день закончен!") 64 | return 65 | case transferPoint <- power: 66 | fmt.Println("Я шахтёр номер:", n, "Передал уголь:", power) 67 | } 68 | 69 | } 70 | } 71 | */ 72 | 73 | // MinerPool -- функция, запускающая minerCount шахтёров, 74 | // Позволяющая потребителям MinerPool функции получать уголь от запущенных шахтёров 75 | // И контролирующая закрытие канала общения 76 | func MinerPool(ctx context.Context, minerCount int) <-chan int { 77 | coalTransferPoint := make(chan int) 78 | 79 | wg := &sync.WaitGroup{} 80 | 81 | for i := 1; i <= minerCount; i++ { 82 | wg.Add(1) 83 | go Miner(ctx, wg, coalTransferPoint, i, i*10) 84 | } 85 | 86 | go func() { 87 | wg.Wait() 88 | close(coalTransferPoint) 89 | }() 90 | 91 | return coalTransferPoint 92 | } 93 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/15. Тело HTTP ответа и HTTP статус коды/3. Управление финансами/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net/http" 7 | "strconv" 8 | "sync" 9 | ) 10 | 11 | var mtx = sync.Mutex{} 12 | var money = 1000 // usd 13 | var bank = 0 // usd 14 | 15 | func payHandler(w http.ResponseWriter, r *http.Request) { 16 | httpRequestBody, err := io.ReadAll(r.Body) 17 | if err != nil { 18 | w.WriteHeader(http.StatusInternalServerError) 19 | 20 | msg := "fail to read HTTP body:" + err.Error() 21 | fmt.Println(msg) 22 | _, err = w.Write([]byte(msg)) 23 | if err != nil { 24 | fmt.Println("fail to write HTTP response:", err) 25 | } 26 | return 27 | } 28 | 29 | httpRequestBodyString := string(httpRequestBody) 30 | 31 | paymentAmount, err := strconv.Atoi(httpRequestBodyString) 32 | if err != nil { 33 | w.WriteHeader(http.StatusBadRequest) 34 | 35 | msg := "fail to convert HTTP body to integer:" + err.Error() 36 | fmt.Println(msg) 37 | _, err = w.Write([]byte(msg)) 38 | if err != nil { 39 | fmt.Println("fail to write HTTP response:", err) 40 | } 41 | return 42 | } 43 | 44 | mtx.Lock() 45 | if money-paymentAmount >= 0 { 46 | money -= paymentAmount 47 | 48 | msg := "Оплата прошла успешно:" + strconv.Itoa(money) 49 | fmt.Println(msg) 50 | _, err = w.Write([]byte(msg)) 51 | if err != nil { 52 | fmt.Println("fail to write HTTP response:", err) 53 | } 54 | } 55 | mtx.Unlock() 56 | } 57 | 58 | // Нет добавленных HTTP ответов и HTTP статус кодов 59 | func saveHandler(w http.ResponseWriter, r *http.Request) { 60 | httpRequestBody, err := io.ReadAll(r.Body) 61 | if err != nil { 62 | fmt.Println("fail to read HTTP request body:", err) 63 | return 64 | } 65 | 66 | httpRequestBodyString := string(httpRequestBody) 67 | 68 | saveAmount, err := strconv.Atoi(httpRequestBodyString) 69 | if err != nil { 70 | fmt.Println("fail to convert string to integer:", err) 71 | } 72 | 73 | mtx.Lock() 74 | if saveAmount <= money { 75 | bank += saveAmount 76 | money -= saveAmount 77 | fmt.Println("Денег в копилке:", bank) 78 | fmt.Println("Балланс кошелька:", money) 79 | } 80 | mtx.Unlock() 81 | } 82 | 83 | func main() { 84 | http.HandleFunc("/pay", payHandler) 85 | http.HandleFunc("/save", saveHandler) 86 | 87 | fmt.Println("Запускаю HTTP сервер!") 88 | err := http.ListenAndServe(":9091", nil) 89 | if err != nil { 90 | fmt.Println("Ошибка во время работы HTTP сервера:", err) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Часть 1. Основы программирования/8. Структуры/3. Структура User с методами и конструктором/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type User struct { 6 | // Имя пользователя 7 | // Правило: имя должно быть не пустое 8 | Name string 9 | 10 | // Возраст пользователя 11 | // Правило: возраст должен быть больше нуля и меньше 150 12 | Age int 13 | 14 | // Номер телефона пользователя 15 | // Правило: номер телефона должен быть не пустым 16 | PhoneNumber string 17 | 18 | // Закрыт ли профиль пользователя? 19 | IsClose bool 20 | 21 | // Социальный рейтинг пользователя 22 | // Правило: рейтинг должен быть больше либо равен нулю, но меньше либо равен десяти 23 | Rating float64 24 | } 25 | 26 | func NewUser( 27 | name string, 28 | age int, 29 | phoneNumber string, 30 | isClose bool, 31 | rating float64, 32 | ) User { 33 | fmt.Println("Валидирую имя!") 34 | if name == "" { 35 | fmt.Println("Имя не прошло валидацию :(") 36 | return User{} 37 | } 38 | fmt.Println("Имя прошло валидацию!") 39 | 40 | fmt.Println("Валидирую возраст!") 41 | if age <= 0 || age >= 150 { 42 | fmt.Println("Возраст не прошёл валидацию :(") 43 | return User{} 44 | } 45 | fmt.Println("Возраст прошёл валидацию!") 46 | 47 | fmt.Println("Валидирую номер телефона!") 48 | if phoneNumber == "" { 49 | fmt.Println("Номер телефона не прошёл валидацию :(") 50 | return User{} 51 | } 52 | fmt.Println("Номер телефона прошёл валидацию!") 53 | 54 | fmt.Println("Валидирую рейтинг!") 55 | if rating < 0.0 || rating > 10.0 { 56 | fmt.Println("Рейтинг не прошёл валидацию :(") 57 | return User{} 58 | } 59 | fmt.Println("Рейтинг прошёл валидацию!") 60 | 61 | fmt.Println("Валидация в конструкторе успешно завершена!") 62 | return User{ 63 | Name: name, 64 | Age: age, 65 | PhoneNumber: phoneNumber, 66 | IsClose: isClose, 67 | Rating: rating, 68 | } 69 | } 70 | 71 | func (u *User) ChangeName(newName string) { 72 | if newName != "" { 73 | u.Name = newName 74 | } 75 | } 76 | 77 | func (u *User) ChangeAge(newAge int) { 78 | if newAge > 0 && newAge < 150 { 79 | u.Age = newAge 80 | } 81 | } 82 | 83 | func (u *User) ChangePhoneNumber(newPhoneNumber string) { 84 | if newPhoneNumber != "" { 85 | u.PhoneNumber = newPhoneNumber 86 | } 87 | } 88 | 89 | func (u *User) CloseAccount() { 90 | // закрыть аккаунт 91 | u.IsClose = true 92 | } 93 | 94 | func (u *User) OpenAccount() { 95 | // открыть аккаунт 96 | u.IsClose = false 97 | } 98 | 99 | func (u *User) RatingUp(ratingDiff float64) { 100 | if u.Rating+ratingDiff <= 10.0 { 101 | u.Rating += ratingDiff 102 | } 103 | } 104 | 105 | func (u *User) RatingDown(ratingDiff float64) { 106 | if u.Rating-ratingDiff >= 0.0 { 107 | u.Rating -= ratingDiff 108 | } 109 | } 110 | 111 | func main() { 112 | user1 := NewUser( 113 | "Иван", 114 | 50, 115 | "+7 (911) 911 91-91", 116 | true, 117 | 5.5, 118 | ) 119 | 120 | user2 := NewUser( 121 | "Пётр", 122 | 60, 123 | "+7 (922) 922 92-92", 124 | false, 125 | 500.5, 126 | ) 127 | 128 | user1.RatingUp(1.5) 129 | user2.CloseAccount() 130 | 131 | fmt.Println("user1:", user1) 132 | fmt.Println("user2:", user2) 133 | } 134 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/1. Интерфейсы/2. Модуль проведения оплат/payments/payments.go: -------------------------------------------------------------------------------- 1 | package payments 2 | 3 | type PaymentMethod interface { 4 | Pay(usd int) int 5 | Cancel(id int) 6 | } 7 | 8 | type PaymentModule struct { 9 | paymentMethod PaymentMethod 10 | paymentsInfo map[int]PaymentsInfo 11 | } 12 | 13 | func NewPaymentModule(paymentMethod PaymentMethod) *PaymentModule { 14 | return &PaymentModule{ 15 | paymentMethod: paymentMethod, 16 | paymentsInfo: make(map[int]PaymentsInfo), 17 | } 18 | } 19 | 20 | // Метод Pay() 21 | // Принимает: 22 | // - Описание проводимой оплаты 23 | // - Сумму оплаты 24 | // Возвращает: 25 | // - ID проведённой операции 26 | func (p *PaymentModule) Pay(description string, usd int) int { 27 | // Проводим оплату через выбранный метод проведения оплат 28 | // В ответ получаем ID проведённой оплаты 29 | id := p.paymentMethod.Pay(usd) 30 | 31 | // Собираем всю информацию об оплате в одну структуру 32 | info := PaymentsInfo{ 33 | Description: description, 34 | USD: usd, 35 | Cancelled: false, 36 | } 37 | 38 | // Сохраняем собранную информацию об оплате 39 | // В качестве ключа: ID проведённой операции 40 | p.paymentsInfo[id] = info 41 | 42 | // Возвращаем ID операции 43 | return id 44 | } 45 | 46 | // Метод Cancel() 47 | // Принимает: 48 | // - ID операции 49 | // Возвращает: 50 | // - Ничего не возвращает 51 | func (p *PaymentModule) Cancel(id int) { 52 | // Получаем информацию об оплате по переданному ID 53 | info, ok := p.paymentsInfo[id] 54 | // Проверяем, была ли вообще ранее проведена оплата с переданным ID 55 | if !ok { 56 | // Если оплата не была проведена, то просто завершаем выполнение текущего метода 57 | return 58 | } 59 | 60 | // Если оплата была проведена, то отменяем её через выбранный метод проведения оплат 61 | p.paymentMethod.Cancel(id) 62 | 63 | // Сохраняем информацию о том, то мы отменили оплату с определённым ID 64 | info.Cancelled = true 65 | p.paymentsInfo[id] = info 66 | } 67 | 68 | // Метод Info() 69 | // Принимает: 70 | // - ID операции 71 | // Возвращает: 72 | // - Информацию о проведённой операции 73 | func (p *PaymentModule) Info(id int) PaymentsInfo { 74 | // Получаем информацию об оплате по переданному ID 75 | info, ok := p.paymentsInfo[id] 76 | // Проверяем, была ли вообще ранее проведена оплата с переданным ID 77 | if !ok { 78 | // Если оплата не была проведена, то просто возвращаем пустую информацию об оплате 79 | return PaymentsInfo{} 80 | } 81 | 82 | // Если оплата была проведена, то возвращаем найденную информацию об этой операции 83 | return info 84 | } 85 | 86 | // Метод AllInfo() 87 | // Принимает: 88 | // - Ничего не принимает 89 | // Возвращает: 90 | // - Информацию о всех проведённых операциях 91 | func (p *PaymentModule) AllInfo() map[int]PaymentsInfo { 92 | // Создаём временную мапу tmp, чтобы защитить мапу p.paymentsInfo от внешнего воздействия потребителями метода AllInfo() 93 | tmp := make(map[int]PaymentsInfo, len(p.paymentsInfo)) 94 | 95 | // Перекопирукм во временную мапу все значения из основной мапы 96 | for k, v := range p.paymentsInfo { 97 | tmp[k] = v 98 | } 99 | 100 | // Возвращаем временную мапу, в которой лежат скопированные из основной мапы данные 101 | return tmp 102 | } 103 | -------------------------------------------------------------------------------- /Часть 2. Продвинутый Golang и REST API/20. REST API. Теория и практика./1. Список дел/http/handlers.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "net/http" 8 | "restapi/todo" 9 | "time" 10 | 11 | "github.com/gorilla/mux" 12 | ) 13 | 14 | type HTTPHandlers struct { 15 | todoList *todo.List 16 | } 17 | 18 | func NewHTTPHandlers(todoList *todo.List) *HTTPHandlers { 19 | return &HTTPHandlers{ 20 | todoList: todoList, 21 | } 22 | } 23 | 24 | /* 25 | pattern: /tasks 26 | method: POST 27 | info: JSON in HTTP request body 28 | 29 | succeed: 30 | - status code: 201 Created 31 | - response body: JSON represent created task 32 | 33 | failed: 34 | - status code: 400, 409, 500, ... 35 | - response body: JSON with error + time 36 | */ 37 | func (h *HTTPHandlers) HandleCreateTask(w http.ResponseWriter, r *http.Request) { 38 | var taskDTO TaskDTO 39 | if err := json.NewDecoder(r.Body).Decode(&taskDTO); err != nil { 40 | errDTO := ErrorDTO{ 41 | Message: err.Error(), 42 | Time: time.Now(), 43 | } 44 | 45 | http.Error(w, errDTO.ToString(), http.StatusBadRequest) 46 | return 47 | } 48 | 49 | if err := taskDTO.ValidateForCreate(); err != nil { 50 | errDTO := ErrorDTO{ 51 | Message: err.Error(), 52 | Time: time.Now(), 53 | } 54 | 55 | http.Error(w, errDTO.ToString(), http.StatusBadRequest) 56 | return 57 | } 58 | 59 | todoTask := todo.NewTask(taskDTO.Title, taskDTO.Description) 60 | if err := h.todoList.AddTask(todoTask); err != nil { 61 | errDTO := ErrorDTO{ 62 | Message: err.Error(), 63 | Time: time.Now(), 64 | } 65 | 66 | if errors.Is(err, todo.ErrTaskAlreadyExists) { 67 | http.Error(w, errDTO.ToString(), http.StatusConflict) 68 | } else { 69 | http.Error(w, errDTO.ToString(), http.StatusInternalServerError) 70 | } 71 | 72 | return 73 | } 74 | 75 | b, err := json.MarshalIndent(todoTask, "", " ") 76 | if err != nil { 77 | panic(err) 78 | } 79 | 80 | w.WriteHeader(http.StatusCreated) 81 | if _, err := w.Write(b); err != nil { 82 | fmt.Println("failed to write http response:", err) 83 | return 84 | } 85 | } 86 | 87 | /* 88 | pattern: /tasks/{title} 89 | method: GET 90 | info: pattern 91 | 92 | succeed: 93 | - status code: 200 Ok 94 | - response body: JSON represented found task 95 | 96 | failed: 97 | - status code: 400, 404, 500, ... 98 | - response body: JSON with error + time 99 | */ 100 | func (h *HTTPHandlers) HandleGetTask(w http.ResponseWriter, r *http.Request) { 101 | title := mux.Vars(r)["title"] 102 | 103 | task, err := h.todoList.GetTask(title) 104 | if err != nil { 105 | errDTO := ErrorDTO{ 106 | Message: err.Error(), 107 | Time: time.Now(), 108 | } 109 | 110 | if errors.Is(err, todo.ErrTaskNotFound) { 111 | http.Error(w, errDTO.ToString(), http.StatusNotFound) 112 | } else { 113 | http.Error(w, errDTO.ToString(), http.StatusInternalServerError) 114 | } 115 | 116 | return 117 | } 118 | 119 | b, err := json.MarshalIndent(task, "", " ") 120 | if err != nil { 121 | panic(err) 122 | } 123 | 124 | w.WriteHeader(http.StatusOK) 125 | if _, err := w.Write(b); err != nil { 126 | fmt.Println("failed to write http response:", err) 127 | return 128 | } 129 | } 130 | 131 | /* 132 | pattern: /tasks 133 | method: GET 134 | info: - 135 | 136 | succeed: 137 | - status code: 200 Ok 138 | - response body: JSON represented found tasks 139 | 140 | failed: 141 | - status code: 400, 500, ... 142 | - response body: JSON with error + time 143 | */ 144 | func (h *HTTPHandlers) HandleGetAllTasks(w http.ResponseWriter, r *http.Request) { 145 | tasks := h.todoList.ListTasks() 146 | b, err := json.MarshalIndent(tasks, "", " ") 147 | if err != nil { 148 | panic(err) 149 | } 150 | 151 | w.WriteHeader(http.StatusOK) 152 | if _, err := w.Write(b); err != nil { 153 | fmt.Println("failed to write http response:", err) 154 | return 155 | } 156 | } 157 | 158 | /* 159 | pattern: /tasks?completed=true <<--- ребята тут я зафакапил, конечно же, если мы получаем список НЕвыполненных задач, то в query параметре должно быть completed=false, а не true 160 | method: GET 161 | info: query params 162 | 163 | succeed: 164 | - status code: 200 Ok 165 | - response body: JSON represented found tasks 166 | 167 | failed: 168 | - status code: 400, 500, ... 169 | - response body: JSON with error + time 170 | */ 171 | func (h *HTTPHandlers) HandleGetAllUncompletedTasks(w http.ResponseWriter, r *http.Request) { 172 | uncompletedTasks := h.todoList.ListUncompletedTasks() 173 | b, err := json.MarshalIndent(uncompletedTasks, "", " ") 174 | if err != nil { 175 | panic(err) 176 | } 177 | 178 | w.WriteHeader(http.StatusOK) 179 | if _, err := w.Write(b); err != nil { 180 | fmt.Println("failed to write http response:", err) 181 | return 182 | } 183 | } 184 | 185 | /* 186 | pattern: /tasks/{title} 187 | method: PATCH 188 | info: pattern + JSON in request body 189 | 190 | succeed: 191 | - status code: 200 Ok 192 | - response body: JSON represented changed task 193 | 194 | failed: 195 | - status code: 400, 409, 500, ... 196 | - response body: JSON with error + time 197 | */ 198 | func (h *HTTPHandlers) HandleCompleteTask(w http.ResponseWriter, r *http.Request) { 199 | var completeDTO CompleteTaskDTO 200 | if err := json.NewDecoder(r.Body).Decode(&completeDTO); err != nil { 201 | errDTO := ErrorDTO{ 202 | Message: err.Error(), 203 | Time: time.Now(), 204 | } 205 | 206 | http.Error(w, errDTO.ToString(), http.StatusBadRequest) 207 | return 208 | } 209 | 210 | title := mux.Vars(r)["title"] 211 | 212 | var ( 213 | changedTask todo.Task 214 | err error 215 | ) 216 | 217 | if completeDTO.Complete { 218 | changedTask, err = h.todoList.CompleteTask(title) 219 | } else { 220 | changedTask, err = h.todoList.UncompleteTask(title) 221 | } 222 | 223 | if err != nil { 224 | errDTO := ErrorDTO{ 225 | Message: err.Error(), 226 | Time: time.Now(), 227 | } 228 | 229 | if errors.Is(err, todo.ErrTaskNotFound) { 230 | http.Error(w, errDTO.ToString(), http.StatusNotFound) 231 | } else { 232 | http.Error(w, errDTO.ToString(), http.StatusInternalServerError) 233 | } 234 | 235 | return 236 | } 237 | 238 | b, err := json.MarshalIndent(changedTask, "", " ") 239 | if err != nil { 240 | panic(err) 241 | } 242 | 243 | if _, err := w.Write(b); err != nil { 244 | fmt.Println("failed to write http response:", err) 245 | return 246 | } 247 | } 248 | 249 | /* 250 | pattern: /tasks/{title} 251 | method: DELETE 252 | info: pattern 253 | 254 | succeed: 255 | - status code: 204 No Content 256 | - response body: - 257 | 258 | failed: 259 | - status code: 400, 404, 500, ... 260 | - response body: JSON with error + time 261 | */ 262 | func (h *HTTPHandlers) HandleDeleteTask(w http.ResponseWriter, r *http.Request) { 263 | title := mux.Vars(r)["title"] 264 | 265 | if err := h.todoList.DeleteTask(title); err != nil { 266 | errDTO := ErrorDTO{ 267 | Message: err.Error(), 268 | Time: time.Now(), 269 | } 270 | 271 | if errors.Is(err, todo.ErrTaskNotFound) { 272 | http.Error(w, errDTO.ToString(), http.StatusNotFound) 273 | } else { 274 | http.Error(w, errDTO.ToString(), http.StatusInternalServerError) 275 | } 276 | 277 | return 278 | } 279 | 280 | w.WriteHeader(http.StatusNoContent) 281 | } 282 | --------------------------------------------------------------------------------