Изучите Go за 10 минут
Go (также известный как Golang) — это статически типизированный компилируемый язык программирования, разработанный в Google. Он известен своей простотой, эффективностью и отличной поддержкой конкурентности. Это руководство поможет быстро изучить программирование на Go.
1. Написание первой программы на Go
Начнем с простой программы. Создайте файл с именем hello.go
и введите следующий код:
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
Сохраните файл и выполните следующую команду в терминале:
go run hello.go
Результат будет:
Hello, World!
Эта простая программа демонстрирует базовую структуру Go:
package main
объявляет имя пакетаimport "fmt"
импортирует пакет форматирования для операций ввода-выводаfunc main()
— точка входа в программуfmt.Println()
выводит текст в консоль
2. Базовый синтаксис
Go имеет чистый и простой синтаксис. В отличие от Python, Go использует фигурные скобки {}
для определения блоков кода и требует точки с запятой в конце операторов (хотя они обычно вставляются автоматически).
// Это однострочный комментарий
fmt.Println("Hello, World!")
/*
Это многострочный комментарий,
занимающий несколько строк
*/
Основные правила синтаксиса в Go:
- Блоки кода: Определяются фигурными скобками
{}
- Комментарии: Однострочные комментарии начинаются с
//
, многострочные с/* */
- Операторы: Заканчиваются точками с запятой (вставляются автоматически)
- Объявление пакета: Каждый файл начинается с объявления пакета
3. Переменные и типы данных
Go статически типизирован, что означает необходимость объявления типов переменных. Однако Go поддерживает вывод типов с помощью оператора :=
.
Способы объявления переменных:
// Явное объявление типа
var name string = "John"
var age int = 25
// Вывод типа
name := "John"
age := 25
// Объявление нескольких переменных
var x, y int = 10, 20
x, y := 10, 20
Основные базовые типы данных в Go:
- Целочисленные типы:
int
,int8
,int16
,int32
,int64
,uint
,uint8
,uint16
,uint32
,uint64
,uintptr
- Вещественные типы:
float32
,float64
- Строки:
string
- Логический тип:
bool
- Комплексные типы:
complex64
,complex128
3.1 Числовые типы
Go предоставляет различные числовые типы для разных случаев использования:
// Целочисленные типы
var age int = 25
var smallNumber int8 = 127
var largeNumber int64 = 9223372036854775807
// Вещественные типы
var temperature float32 = 36.5
var pi float64 = 3.14159265359
// Комплексные числа
var complexNum complex64 = 3 + 4i
3.2 Строковый тип
Строки в Go — это последовательности байтов и они неизменяемы:
// Объявление строки
var greeting string = "Hello, Go!"
name := "Alice"
// Операции со строками
fmt.Println(len(greeting)) // Длина строки
fmt.Println(greeting[0]) // Доступ к первому символу (байту)
fmt.Println(greeting[0:5]) // Срез строки
fmt.Println(strings.ToUpper(name)) // Преобразование в верхний регистр
3.3 Логический тип
Логический тип имеет два значения: true
и false
:
var isActive bool = true
var isComplete bool = false
// Логические операции
result1 := true && false // false
result2 := true || false // true
result3 := !true // false
4. Константы
Константы объявляются с помощью ключевого слова const
и не могут быть изменены:
const Pi = 3.14159
const MaxUsers = 1000
// Несколько констант
const (
StatusOK = 200
StatusNotFound = 404
StatusError = 500
)
// Типизированные константы
const Version string = "1.0.0"
5. Структуры данных
Go предоставляет несколько встроенных структур данных для хранения и обработки информации.
5.1 Массивы
Массивы — это последовательности фиксированного размера элементов одного типа:
// Объявление массива
var numbers [5]int = [5]int{1, 2, 3, 4, 5}
names := [3]string{"Alice", "Bob", "Charlie"}
// Доступ к элементам
fmt.Println(numbers[0]) // 1
numbers[0] = 10 // Изменение элемента
// Длина массива
fmt.Println(len(numbers)) // 5
5.2 Срезы
Срезы — это динамические массивы, которые могут расти и уменьшаться:
// Объявление среза
numbers := []int{1, 2, 3, 4, 5}
var emptySlice []int
// Создание срезов из массивов
arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:4] // [2, 3, 4]
// Операции со срезами
numbers = append(numbers, 6) // Добавление элемента
numbers = append(numbers, 7, 8, 9) // Добавление нескольких элементов
// Емкость и длина среза
fmt.Println(len(numbers)) // Длина: 9
fmt.Println(cap(numbers)) // Емкость: 10 (может варьироваться)
5.3 Карты
Карты — это неупорядоченные коллекции пар ключ-значение:
// Объявление карты
student := map[string]interface{}{
"name": "John",
"age": 20,
"major": "Computer Science",
}
// Альтернативное объявление
var scores map[string]int = make(map[string]int)
scores["math"] = 95
scores["science"] = 88
// Доступ и изменение
fmt.Println(student["name"])
student["age"] = 21
student["gpa"] = 3.8
// Безопасный доступ
if phone, exists := student["phone"]; exists {
fmt.Println(phone)
} else {
fmt.Println("Телефон не указан")
}
// Итерация по карте
for key, value := range student {
fmt.Printf("%s: %v\n", key, value)
}
5.4 Структуры
Структуры — это коллекции полей, которые могут иметь разные типы:
// Определение структуры
type Person struct {
Name string
Age int
City string
}
// Создание экземпляров структуры
person1 := Person{"Alice", 25, "New York"}
person2 := Person{
Name: "Bob",
Age: 30,
City: "London",
}
// Доступ к полям
fmt.Println(person1.Name)
person1.Age = 26
6. Операции и операторы
Go предоставляет богатый набор операторов для различных вычислений и сравнений.
- Арифметические операторы:
+
,-
,*
,/
,%
(остаток от деления) - Операторы сравнения:
==
,!=
,>
,<
,>=
,<=
- Логические операторы:
&&
,||
,!
- Побитовые операторы:
&
,|
,^
,<<
,>>
- Операторы присваивания:
=
,+=
,-=
,*=
,/=
6.1 Арифметические операторы
a, b := 10, 3
fmt.Printf("Сложение: %d\n", a + b) // 13
fmt.Printf("Вычитание: %d\n", a - b) // 7
fmt.Printf("Умножение: %d\n", a * b) // 30
fmt.Printf("Деление: %d\n", a / b) // 3
fmt.Printf("Остаток от деления: %d\n", a % b) // 1
6.2 Операторы сравнения
x, y := 5, 10
fmt.Printf("Равно: %t\n", x == y) // false
fmt.Printf("Не равно: %t\n", x != y) // true
fmt.Printf("Больше: %t\n", x > y) // false
fmt.Printf("Меньше: %t\n", x < y) // true
6.3 Логические операторы
a, b := true, false
fmt.Printf("Логическое И: %t\n", a && b) // false
fmt.Printf("Логическое ИЛИ: %t\n", a || b) // true
fmt.Printf("Логическое НЕ: %t\n", !a) // false
7. Управляющие конструкции
Go предоставляет несколько управляющих конструкций для управления выполнением программы.
7.1 Условные операторы if
age := 20
if age >= 18 {
fmt.Println("Взрослый")
} else if age >= 13 {
fmt.Println("Подросток")
} else {
fmt.Println("Ребенок")
}
// if с коротким оператором
if score := 85; score >= 90 {
fmt.Println("Оценка: A")
} else if score >= 80 {
fmt.Println("Оценка: B")
} else {
fmt.Println("Оценка: C")
}
7.2 Циклы for
Go имеет только одну конструкцию цикла: for
// Базовый цикл for
for i := 0; i < 5; i++ {
fmt.Println(i)
}
// Цикл в стиле while
count := 0
for count < 5 {
fmt.Println(count)
count++
}
// Бесконечный цикл
for {
fmt.Println("Этот цикл будет выполняться вечно")
break // Используйте break для выхода
}
// Цикл range (для срезов, массивов, карт)
fruits := []string{"apple", "banana", "cherry"}
for index, fruit := range fruits {
fmt.Printf("%d: %s\n", index, fruit)
}
7.3 Операторы switch
day := "Monday"
switch day {
case "Monday":
fmt.Println("Начало недели")
case "Friday":
fmt.Println("Выходные близко")
case "Saturday", "Sunday":
fmt.Println("Выходные!")
default:
fmt.Println("Обычный день")
}
// Switch без выражения
score := 85
switch {
case score >= 90:
fmt.Println("Оценка: A")
case score >= 80:
fmt.Println("Оценка: B")
case score >= 70:
fmt.Println("Оценка: C")
default:
fmt.Println("Оценка: F")
}
8. Функции
Функции в Go являются объектами первого класса и поддерживают множественные возвращаемые значения.
8.1 Базовые функции
func greet(name string) string {
return "Hello, " + name + "!"
}
// Вызов функции
message := greet("John")
fmt.Println(message)
8.2 Множественные возвращаемые значения
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("нельзя делить на ноль")
}
return a / b, nil
}
// Использование множественных возвращаемых значений
result, err := divide(10, 2)
if err != nil {
fmt.Println("Ошибка:", err)
} else {
fmt.Println("Результат:", result)
}
8.3 Именованные возвращаемые значения
func calculateRectangle(width, height float64) (area float64, perimeter float64) {
area = width * height
perimeter = 2 * (width + height)
return // "голый" return
}
area, perimeter := calculateRectangle(5, 3)
fmt.Printf("Площадь: %.2f, Периметр: %.2f\n", area, perimeter)
8.4 Функции с переменным числом аргументов
func sum(numbers ...int) int {
total := 0
for _, num := range numbers {
total += num
}
return total
}
fmt.Println(sum(1, 2, 3, 4)) // 10
fmt.Println(sum(5, 10, 15)) // 30
9. Указатели
Go имеет указатели, но с более простым синтаксисом, чем C/C++:
func modifyValue(x *int) {
*x = *x * 2
}
func main() {
value := 10
fmt.Println("До:", value) // 10
modifyValue(&value)
fmt.Println("После:", value) // 20
}
10. Методы
Методы — это функции с получателем:
type Rectangle struct {
Width float64
Height float64
}
// Метод с получателем по значению
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
// Метод с получателем по указателю
func (r *Rectangle) Scale(factor float64) {
r.Width *= factor
r.Height *= factor
}
rect := Rectangle{Width: 5, Height: 3}
fmt.Println("Площадь:", rect.Area()) // 15
rect.Scale(2)
fmt.Println("Масштабированная площадь:", rect.Area()) // 60
11. Интерфейсы
Интерфейсы определяют сигнатуры методов, которые могут реализовывать типы:
type Shape interface {
Area() float64
Perimeter() float64
}
type Circle struct {
Radius float64
}
func (c Circle) Area() float64 {
return 3.14159 * c.Radius * c.Radius
}
func (c Circle) Perimeter() float64 {
return 2 * 3.14159 * c.Radius
}
func printShapeInfo(s Shape) {
fmt.Printf("Площадь: %.2f, Периметр: %.2f\n", s.Area(), s.Perimeter())
}
circle := Circle{Radius: 5}
printShapeInfo(circle)
12. Обработка ошибок
Go использует явную обработку ошибок вместо исключений:
func readFile(filename string) (string, error) {
data, err := os.ReadFile(filename)
if err != nil {
return "", fmt.Errorf("не удалось прочитать файл %s: %w", filename, err)
}
return string(data), nil
}
content, err := readFile("example.txt")
if err != nil {
fmt.Println("Ошибка:", err)
return
}
fmt.Println("Содержимое:", content)
13. Конкурентность с горутинами
Горутины — это легковесные потоки, управляемые средой выполнения Go:
func worker(id int) {
for i := 0; i < 3; i++ {
fmt.Printf("Работник %d: %d\n", id, i)
time.Sleep(time.Millisecond * 100)
}
}
func main() {
// Запуск нескольких горутин
for i := 1; i <= 3; i++ {
go worker(i)
}
// Ожидание завершения горутин
time.Sleep(time.Second)
fmt.Println("Все работники завершили работу")
}
14. Каналы
Каналы используются для общения между горутинами:
func producer(ch chan<- int) {
for i := 0; i < 5; i++ {
ch <- i // Отправка значения в канал
time.Sleep(time.Millisecond * 100)
}
close(ch) // Закрытие канала по завершении
}
func consumer(ch <-chan int) {
for value := range ch {
fmt.Println("Получено:", value)
}
}
func main() {
ch := make(chan int, 3) // Буферизованный канал
go producer(ch)
consumer(ch)
fmt.Println("Общение через канал завершено")
}
15. Операции с файлами
Go предоставляет простые методы для чтения и записи файлов:
// Чтение файлов
data, err := os.ReadFile("example.txt")
if err != nil {
fmt.Println("Ошибка чтения файла:", err)
return
}
fmt.Println("Содержимое файла:", string(data))
// Запись файлов
content := "Hello, Go!\n"
err = os.WriteFile("output.txt", []byte(content), 0644)
if err != nil {
fmt.Println("Ошибка записи файла:", err)
return
}
fmt.Println("Файл успешно записан")
16. Пакеты и модули
Модули Go управляют зависимостями и версиями пакетов:
// Импорт стандартных библиотечных пакетов
import (
"fmt"
"math"
"strings"
)
func main() {
fmt.Println(math.Sqrt(16)) // 4
fmt.Println(strings.ToUpper("go")) // GO
}
Чтобы создать собственный пакет, создайте каталог с именем вашего пакета и экспортируйте функции, используя заглавные буквы в их именах.
17. Тестирование
Go имеет встроенную поддержку тестирования:
// В файле math_test.go
package main
import "testing"
func TestAdd(t *testing.T) {
result := add(2, 3)
expected := 5
if result != expected {
t.Errorf("add(2, 3) = %d; ожидалось %d", result, expected)
}
}
func add(a, b int) int {
return a + b
}
Запустите тесты командой: go test
18. Лучшие практики
- Используйте
gofmt
для форматирования кода - Следуйте соглашениям об именовании в Go (camelCase для переменных, PascalCase для экспортируемых элементов)
- Обрабатывайте ошибки явно
- Используйте интерфейсы для абстракции
- Предпочитайте композицию наследованию
- Пишите комплексные тесты
- Используйте стандартную библиотеку везде, где это возможно
Это руководство охватывает основные возможности программирования на Go. С практикой вы сможете создавать эффективные и конкурентные приложения, используя мощные возможности Go.