← Назад к курсу

Бесплатный пробный урок: Golang Developer

Пройдите пару настоящих уроков этого курса — регистрация не требуется.

01

Урок 1: Пакеты, комментарии, переменные и операторы

Пакеты. Комментарии.

Любой код в Go хранится внутри пакета. Пакет — это папка, которая содержит файлы .go.

Давайте рассмотрим первый простой пример создания программы на Go:

main.go
package main

import "fmt"

func main() {
    fmt.Println("Salem Bitlab!")
}
Output:Salem Bitlab!
GOLANG
Результат

Для выполнения данной программы мы использовали пакеты main и fmt.

package main — это главный пакет. Он обязательно должен содержать функцию func main(), которая является точкой входа в программу. При запуске Go-приложения именно эта функция вызывается первой.

package fmt — стандартный пакет, который используется для вывода данных в консоль. Помимо вывода, он также поддерживает форматированный ввод и вывод данных.

Когда программа становится больше, читать и понимать код становится сложнее. Чтобы упростить понимание логики программы, используются комментарии.

Комментарии нужны для пояснения кода и его логического разделения. Они не участвуют в компиляции и никак не влияют на выполнение программы.

Виды комментариев

Однострочные комментарии

main.go
package main

import "fmt"

func main() {
    fmt.Println("I like Bitlab Academy!") // вывод текста в консоль
}
Output:I like Bitlab Academy!
GOLANG
Результат

Однострочный комментарий используется для краткого пояснения конкретной строки или части кода.

Многострочные комментарии

main.go
package main

import "fmt"

/*
    В данной программе
    при помощи пакета "fmt"
    мы отображаем данные
    в консоль
*/
func main() {
    fmt.Println("I like Bitlab Academy!")
}
Output:I like Bitlab Academy!
GOLANG
Результат

Многострочные комментарии используются для подробного описания функций, структур и больших логических блоков кода.

Переменные и типы данных

Go — статически типизированный язык программирования. Компилятор Go перед запуском программы проверяет типы данных, что обеспечивает высокую надёжность, производительность и читаемость кода.

Go — настолько быстрый язык, что я зову его Флэш в мире программирования.

— Сусликов Битлабхан, признанный обществом деятель в области обретения полезных навыков

Перед тем как приступить к знакомству с типами данных, необходимо понять, что такое переменные.

Переменные — это участок памяти, который хранит некоторое значение. Каждая переменная имеет тип данных, который определяет, какие операции с ней можно выполнять.

Объявление переменной выглядит следующим образом:

main.go
package main

import "fmt"

func main() {
    var age int = 22
    fmt.Println(age)
}
Output:22
GOLANG
Результат

Для объявления переменной мы используем ключевое слово var, затем имя переменной и её тип данных. После этого мы можем свободно использовать переменную в программе.

В Go также существует краткая форма объявления переменной:

main.go
package main

import "fmt"

func main() {
    age := 22
    fmt.Println(age)
}
Output:22
GOLANG
Результат

При использовании оператора := Go автоматически определяет тип переменной на основе присваиваемого значения.

Основные типы данных в Go

Для работы с числами:

  • int — целые положительные и отрицательные числа
  • uint — только положительные целые числа
  • float32 — дробные числа (32 бита)
  • float64 — дробные числа (64 бита)
  • complex64 — комплексные числа (2 × float32)
  • complex128 — комплексные числа (2 × float64)

Для работы со строками:

  • string — текстовые данные

Для логических операций:

  • bool — true или false

Для работы с наборами данных:

  • array — массив фиксированной длины
  • slice — массив динамической длины
  • map — структура ключ–значение
  • struct — объединение разных типов данных
  • interface — абстрактный тип данных

Дополнительные типы данных:

  • pointer — указатель
  • function — функция как тип данных
  • channel — взаимодействие между горутинами

Математические операторы

Математические операторы позволяют выполнять операции с числами.

Сложение (+)

a := 2
b := 2
c := a + b // 4
GOLANG
Результат

Вычитание (-)

a := 10
b := 5
c := a - b // 5
GOLANG
Результат

Умножение (*)

a := 3
b := 3
c := a * b // 9
GOLANG
Результат

Деление (/)

a := 6
b := 2
c := a / b // 3
GOLANG
Результат

Остаток от деления (%)

a := 7
b := 3
c := a % b // 1
GOLANG
Результат

Инкремент (++)

a := 7
a++ // 8
GOLANG
Результат

Декремент (--)

a := 7
a-- // 6
GOLANG
Результат

Чтобы закрепить изученный материал, рекомендуется попрактиковаться, решая подготовленные задачи. Удачи!

02

Урок 2: Условные конструкции и логические операторы

Что такое условия в Go?

В реальных программах код не всегда выполняется сверху вниз одинаково. Иногда программа должна принять решение: выполнить один блок кода или другой.

Например:

  • если возраст пользователя больше или равен 18 — разрешить доступ;
  • если пароль правильный — войти в систему;
  • если баланс достаточный — выполнить оплату;
  • если оценка высокая — вывести сообщение об успехе.

Для таких ситуаций в Go используются условные конструкции. Они позволяют программе выбирать, какой код нужно выполнить.

Условие — это выражение, результатом которого всегда является true или false.

Как работает условие?

Условная конструкция проверяет выражение. Если результат выражения равен true, выполняется один блок кода. Если результат равен false, этот блок пропускается или выполняется другой блок.

Конструкция if

Самая простая условная конструкция — это if. Она выполняет код только в том случае, если условие истинно.

main.go
package main

import "fmt"

func main() {
    age := 20

    if age >= 18 {
        fmt.Println("Доступ разрешён")
    }
}
Output:Доступ разрешён
GOLANG
Результат

Здесь программа проверяет условие age >= 18. Значение переменной age равно 20, поэтому условие истинно. Значит, код внутри блока if выполнится.

Важно: в Go условие внутри if не пишется в круглых скобках. Но фигурные скобки { } обязательны.

Конструкция if ... else

Если нужно выполнить один код при истинном условии, а другой код при ложном условии, используется конструкция if ... else.

main.go
package main

import "fmt"

func main() {
    age := 15

    if age >= 18 {
        fmt.Println("Доступ разрешён")
    } else {
        fmt.Println("Доступ запрещён")
    }
}
Output:Доступ запрещён
GOLANG
Результат

Значение age равно 15. Условие age >= 18 возвращает false. Поэтому блок if не выполняется, а выполняется блок else.

Несколько условий: else if

Иногда двух вариантов недостаточно. Например, нужно проверить оценку студента и вывести разный результат. В таком случае используется else if.

main.go
package main

import "fmt"

func main() {
    score := 85

    if score >= 90 {
        fmt.Println("Отлично")
    } else if score >= 75 {
        fmt.Println("Хорошо")
    } else if score >= 50 {
        fmt.Println("Можно лучше")
    } else {
        fmt.Println("Не сдал")
    }
}
Output:Хорошо
GOLANG
Результат

Программа проверяет условия сверху вниз:

score >= 90 — false
score >= 75 — true
выводится Хорошо
остальные условия уже не проверяются

Операторы сравнения

Чтобы строить условия, часто используются операторы сравнения. Они сравнивают значения и возвращают результат true или false.

  • == — равно
  • != — не равно
  • > — больше
  • < — меньше
  • >= — больше или равно
  • <= — меньше или равно
main.go
package main

import "fmt"

func main() {
    a := 10
    b := 5

    fmt.Println(a == b)
    fmt.Println(a != b)
    fmt.Println(a > b)
    fmt.Println(a < b)
}
Output:false true true false
GOLANG
Результат

Логические операторы

Логические операторы позволяют объединять несколько условий. Это полезно, когда одного сравнения недостаточно.

  • && — И, оба условия должны быть true
  • || — ИЛИ, хотя бы одно условие должно быть true
  • ! — НЕ, меняет true на false и false на true

Если нужно проверить несколько правил одновременно, чаще всего используются операторы && и ||.

Пример с оператором &&

Оператор && означает, что оба условия должны быть истинными. Например, пользователь может войти в систему только если логин и пароль правильные.

main.go
package main

import "fmt"

func main() {
    login := "admin"
    password := "12345"

    if login == "admin" && password == "12345" {
        fmt.Println("Добро пожаловать")
    } else {
        fmt.Println("Неверный логин или пароль")
    }
}
Output:Добро пожаловать
GOLANG
Результат

Пример с оператором ||

Оператор || означает, что достаточно выполнения хотя бы одного условия. Например, город может называться Astana или Nur-Sultan.

main.go
package main

import "fmt"

func main() {
    city := "Astana"

    if city == "Astana" || city == "Nur-Sultan" {
        fmt.Println("Здравствуй столица")
    } else {
        fmt.Println("Это другой город")
    }
}
Output:Здравствуй столица
GOLANG
Результат

Пример с оператором !

Оператор ! меняет значение логического выражения на противоположное. Если было true, станет false. Если было false, станет true.

main.go
package main

import "fmt"

func main() {
    isBlocked := false

    if !isBlocked {
        fmt.Println("Пользователь активен")
    } else {
        fmt.Println("Пользователь заблокирован")
    }
}
Output:Пользователь активен
GOLANG
Результат

Инициализация внутри if

В Go можно создать переменную прямо внутри конструкции if. Такая переменная будет доступна только внутри этого условия.

main.go
package main

import "fmt"

func main() {
    if age := 19; age >= 18 {
        fmt.Println("Совершеннолетний")
    } else {
        fmt.Println("Несовершеннолетний")
    }
}
Output:Совершеннолетний
GOLANG
Результат

Переменная age создана перед проверкой условия. После завершения конструкции if ... else использовать эту переменную уже нельзя.

Конструкция switch ... case

Если нужно сравнить одно значение с несколькими вариантами, удобно использовать конструкцию switch ... case.

Она делает код чище, когда вариантов много.

main.go
package main

import "fmt"

func main() {
    day := 3

    switch day {
    case 1:
        fmt.Println("Понедельник")
    case 2:
        fmt.Println("Вторник")
    case 3:
        fmt.Println("Среда")
    case 4:
        fmt.Println("Четверг")
    case 5:
        fmt.Println("Пятница")
    default:
        fmt.Println("Выходной или неизвестный день")
    }
}
Output:Среда
GOLANG
Результат

В Go после каждого case не нужно писать break. После выполнения найденного варианта конструкция switch завершается автоматически.

default выполняется тогда, когда ни один case не подошёл.

switch без значения

В Go можно использовать switch без конкретного значения. В таком случае каждый case становится отдельным условием.

main.go
package main

import "fmt"

func main() {
    temperature := 30

    switch {
    case temperature >= 30:
        fmt.Println("Жарко")
    case temperature >= 20:
        fmt.Println("Тепло")
    case temperature >= 10:
        fmt.Println("Прохладно")
    default:
        fmt.Println("Холодно")
    }
}
Output:Жарко
GOLANG
Результат

Практические примеры

Чтобы лучше понять условия, полезно решать простые задачи.

  • Проверить, является ли число положительным или отрицательным.
  • Проверить, является ли число чётным или нечётным.
  • Проверить, может ли пользователь получить доступ по возрасту.
  • Проверить логин и пароль пользователя.
  • Вывести название дня недели по номеру.

Итоги

Условные конструкции позволяют программе принимать решения. Без условий невозможно написать полноценную программу, потому что почти любая логика зависит от разных ситуаций.

  • if используется для простой проверки;
  • else выполняется, если условие ложно;
  • else if нужен для проверки нескольких вариантов;
  • switch удобен, когда нужно сравнить значение с несколькими вариантами;
  • &&, ||, ! позволяют объединять и изменять условия.
03

Урок 3: Циклы и оператор for

Что такое цикл?

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

В программировании очень часто бывают ситуации, когда одно и то же действие нужно повторить несколько раз. Например:

  • вывести числа от 1 до 10;
  • посчитать сумму чисел;
  • прочитать несколько значений с консоли;
  • обработать список студентов;
  • напечатать таблицу умножения.

Без циклов пришлось бы писать одинаковый код много раз вручную. Циклы позволяют сделать код короче, понятнее и удобнее.

В Go есть всего один цикл — for, но он может принимать разные формы.

Как работает цикл?

  • сначала задаётся начальное значение;
  • затем проверяется условие;
  • если условие истинно, выполняется тело цикла;
  • после этого значение изменяется;
  • затем условие проверяется снова.

Классический for

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

Например, если нужно вывести числа от 0 до 4:

main.go
package main

import "fmt"

func main() {
    for i := 0; i < 5; i++ {
        fmt.Println(i)
    }
}
Output:0 1 2 3 4
GOLANG
Результат

Конструкция цикла состоит из трёх частей:

  • i := 0 — инициализация (стартовое значение)
  • i < 5 — условие (пока истинно — цикл работает)
  • i++ — шаг (изменение переменной после каждой итерации)

Таким образом цикл сработал 5 раз — пока i не стал равен 5.

Пример: вывести числа от 1 до 10

Очень частая задача — вывести числа в определённом диапазоне. Для этого можно использовать обычный цикл for.

main.go
package main

import "fmt"

func main() {
    for i := 1; i <= 10; i++ {
        fmt.Println(i)
    }
}
Output:1 2 3 4 5 6 7 8 9 10
GOLANG
Результат

В этом примере переменная i начинается с 1. Цикл работает до тех пор, пока i <= 10. После каждой итерации значение i увеличивается на 1.

Пример: сумма чисел

Циклы часто используются для накопления результата. Например, можно посчитать сумму чисел от 1 до 5.

main.go
package main

import "fmt"

func main() {
    sum := 0

    for i := 1; i <= 5; i++ {
        sum = sum + i
    }

    fmt.Println(sum)
}
Output:15
GOLANG
Результат

Здесь переменная sum хранит общий результат. На каждой итерации мы добавляем к ней текущее значение i.

Как меняется sum:

  • i = 1, sum = 0 + 1 = 1
  • i = 2, sum = 1 + 2 = 3
  • i = 3, sum = 3 + 3 = 6
  • i = 4, sum = 6 + 4 = 10
  • i = 5, sum = 10 + 5 = 15

Пример: вывести только чётные числа

Внутри цикла можно использовать условные конструкции. Например, можно пройтись по числам от 1 до 10 и вывести только чётные числа.

main.go
package main

import "fmt"

func main() {
    for i := 1; i <= 10; i++ {
        if i%2 == 0 {
            fmt.Println(i)
        }
    }
}
Output:2 4 6 8 10
GOLANG
Результат

Условие i%2 == 0 проверяет, делится ли число на 2 без остатка. Если остаток равен 0, значит число чётное.

Форма for как while

В Go нет отдельного ключевого слова while. Но цикл for можно использовать как while, если оставить только условие.

main.go
package main

import "fmt"

func main() {
    i := 1
    for i < 10 {
        fmt.Println(i)
        i++
    }
}
Output:1 2 3 4 5 6 7 8 9
GOLANG
Результат

Как и прежде — цикл работает до тех пор, пока условие истинно. В данном случае — пока i < 10.

Бесконечный цикл

Если написать for без условия, получится бесконечный цикл. Такой цикл будет выполняться бесконечно, пока мы не остановим его вручную или не используем break.

main.go
package main

import "fmt"

func main() {
    i := 1

    for {
        fmt.Println(i)
        i++

        if i > 5 {
            break
        }
    }
}
Output:1 2 3 4 5
GOLANG
Результат

Важно: бесконечный цикл нужно использовать аккуратно. Если забыть условие выхода, программа может работать бесконечно.

Оператор break

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

main.go
package main

import "fmt"

func main() {
    for i := 1; i <= 10; i++ {
        if i == 6 {
            break
        }

        fmt.Println(i)
    }
}
Output:1 2 3 4 5
GOLANG
Результат

Когда i становится равным 6, срабатывает break. Цикл сразу завершается, поэтому число 6 и следующие числа не выводятся.

Оператор continue

Оператор continue пропускает текущую итерацию и сразу переходит к следующей. Он полезен, когда некоторые значения нужно пропустить.

main.go
package main

import "fmt"

func main() {
    for i := 1; i <= 5; i++ {
        if i == 3 {
            continue
        }

        fmt.Println(i)
    }
}
Output:1 2 4 5
GOLANG
Результат

Когда i равно 3, выполняется continue. Поэтому fmt.Println(i) для числа 3 пропускается.

Цикл с вводом данных

Циклы можно использовать для чтения данных с консоли. Например, можно вводить числа до тех пор, пока пользователь не введёт 0.

main.go
package main

import "fmt"

func main() {
    var number int

    for {
        fmt.Scan(&number)

        if number == 0 {
            break
        }

        fmt.Println(number)
    }
}

В этом примере цикл работает бесконечно, но завершается, когда пользователь вводит число 0.

Такой подход часто используется, когда заранее неизвестно, сколько значений введёт пользователь.

Вложенные циклы

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

Один из самых популярных примеров — таблица умножения.

main.go
package main

import "fmt"

func main() {
    for i := 1; i < 10; i++ {
        for j := 1; j < 10; j++ {
            fmt.Print(i*j, "\t")
        }
        fmt.Println()
    }
}
Output:1 2 3 4 5 6 7 8 9 2 4 6 8 10 12 14 16 18 3 6 9 12 15 18 21 24 27 4 8 12 16 20 24 28 32 36 5 10 15 20 25 30 35 40 45 6 12 18 24 30 36 42 48 54 7 14 21 28 35 42 49 56 63 8 16 24 32 40 48 56 64 72 9 18 27 36 45 54 63 72 81
GOLANG
Результат

Получилась таблица умножения: по горизонтали идёт i, по вертикали — j. Каждый из циклов работает, пока переменные меньше 10.

Как это работает:

  • внешний цикл отвечает за строки;
  • внутренний цикл отвечает за столбцы;
  • на каждой итерации выводится результат i * j;
  • после завершения внутреннего цикла выполняется переход на новую строку.

Пример вложенного цикла: прямоугольник из звёздочек

Вложенные циклы часто используются для рисования простых фигур в консоли. Например, можно вывести прямоугольник из символов *.

main.go
package main

import "fmt"

func main() {
    for i := 1; i <= 3; i++ {
        for j := 1; j <= 5; j++ {
            fmt.Print("*")
        }
        fmt.Println()
    }
}
Output:***** ***** *****
GOLANG
Результат

Внешний цикл выполняется 3 раза и создаёт 3 строки. Внутренний цикл выполняется 5 раз и печатает 5 звёздочек в каждой строке.

Цикл for range

В Go часто используется форма for range. Она удобна, когда нужно пройтись по набору данных.

Например, можно пройтись по списку имён:

main.go
package main

import "fmt"

func main() {
    names := []string{"Aibek", "Dana", "Miras"}

    for index, name := range names {
        fmt.Println(index, name)
    }
}
Output:0 Aibek 1 Dana 2 Miras
GOLANG
Результат

Переменная index хранит номер элемента, а переменная name хранит само значение.

Если индекс не нужен

Иногда нам нужно только значение, а индекс не нужен. В таком случае вместо индекса можно использовать символ _.

main.go
package main

import "fmt"

func main() {
    names := []string{"Aibek", "Dana", "Miras"}

    for _, name := range names {
        fmt.Println(name)
    }
}
Output:Aibek Dana Miras
GOLANG
Результат

Символ _ означает, что это значение нам не нужно.

Частые ошибки при работе с циклами

  • забыть изменить переменную цикла;
  • написать условие, которое всегда истинно;
  • создать бесконечный цикл без break;
  • неправильно указать границы цикла;
  • перепутать < и <=.

Мини-практика

Чтобы лучше закрепить циклы, попробуйте написать программы для следующих задач:

  • вывести числа от 1 до 100;
  • вывести только нечётные числа от 1 до 50;
  • посчитать сумму чисел от 1 до N;
  • вывести таблицу умножения для одного числа;
  • вводить числа до тех пор, пока пользователь не введёт 0;
  • найти максимальное число среди введённых чисел;
  • вывести квадрат из символов *.

Итоги

Циклы позволяют выполнять один и тот же код много раз. В Go для этого используется только цикл for, но он может быть записан в разных формах.

  • классический for удобен, когда известны границы цикла;
  • for как while удобен, когда важна только проверка условия;
  • бесконечный for используется вместе с break;
  • break завершает цикл;
  • continue пропускает текущую итерацию;
  • вложенные циклы позволяют работать с таблицами и фигурами;
  • for range используется для прохода по наборам данных.
04

Урок 4: Срезы

Что такое срез?

Срез (slice) — это последовательный набор элементов одного типа. В отличие от массивов, срезы имеют динамическую длину: в них можно добавлять новые элементы и удалять существующие.

Срезы очень похожи на массивы, но намного удобнее в реальной разработке. Если массив имеет фиксированный размер, то срез может увеличиваться по мере необходимости.

Поэтому в Go чаще всего работают именно со срезами, а не с обычными массивами.

Срезы — это как казахский той: можно запланировать мероприятие на 200 человек, а сколько гостей будет в итоге — неизвестно. Может 150? 250? Или все 300? Срезы обладают теми же качествами, что и организаторы тоя — гибкостью.

Мейрам "Пунктуальность" Тойбастаров — тот, кто "никогда" не опаздывает и смыслит в срезах

Главное отличие среза от массива — у среза длина может изменяться во время работы программы.

Массив vs срез

Визуально массив и срез очень похожи, но между ними есть важная разница.

Массив

Размер фиксированный. Если массив создан на 5 элементов, он всегда будет содержать ровно 5 элементов.

Срез

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

В Go срез записывается почти как массив, но без указания размера внутри квадратных скобок.

Создание среза

Срезы создаются почти как массивы, только при создании не указывается длина.

Main.go
package main

import "fmt"

func main() {
    boxers := []string{"Muhammad Ali", "Mike Tyson", "George Foreman", "Joe Frazier"}
    for _, value := range boxers {
        fmt.Println(value)
    }
}
Output:Muhammad Ali Mike Tyson George Foreman Joe Frazier
GOLANG
Результат

Обратите внимание: в [] мы не указали длину — именно поэтому это slice.

Если написать [4]string, это будет массив. Если написать []string, это будет срез.

Срез разных типов

Срез может хранить элементы разных типов данных, но внутри одного среза все элементы должны быть одного типа.

Срез чисел:

numbers := []int{10, 20, 30, 40}

Срез строк:

cities := []string{"Almaty", "Astana", "Paris"}

Срез логических значений:

answers := []bool{true, false, true}

Создание среза через make()

Также срезы можно создавать при помощи функции make():

Main.go
package main

import "fmt"

func main() {
    cities := make([]string, 4)
    cities[0] = "Almaty"
    cities[1] = "Astana"
    cities[2] = "New-York"
    cities[3] = "Washington"

    for _, value := range cities {
        fmt.Println(value)
    }
}
Output:Almaty Astana New-York Washington
GOLANG
Результат

Когда мы пишем make([]string, 4), Go создаёт срез строк длиной 4. После этого мы можем обращаться к элементам по индексам от 0 до 3.

Теперь давайте посмотрим, как добавлять, удалять элементы, и что такое оператор среза.

Длина и вместимость: len и cap

У среза есть две важные характеристики: длина и вместимость.

  • len — сколько элементов сейчас находится в срезе;
  • cap — сколько элементов может поместиться в текущем внутреннем массиве.
Main.go
package main

import "fmt"

func main() {
    numbers := []int{10, 20, 30}

    fmt.Println(len(numbers))
    fmt.Println(cap(numbers))
}
Output:3 3
GOLANG
Результат

В начале len и cap часто равны. Но после добавления элементов через append вместимость может измениться.

Добавление элементов (append)

Для добавления элемента в срез используется функция append(slice, value).

Main.go
package main

import "fmt"

func main() {
    cities := []string{"Almaty", "Astana"}

    cities = append(cities, "Paris")
    cities = append(cities, "Marcel")

    for _, value := range cities {
        fmt.Println(value)
    }
}
Output:Almaty Astana Paris Marcel
GOLANG
Результат

Важно сохранить результат обратно в переменную: cities = append(cities, "Paris"). Функция append возвращает новый срез.

Добавление нескольких элементов

Через append можно добавить сразу несколько элементов.

Main.go
package main

import "fmt"

func main() {
    numbers := []int{1, 2, 3}

    numbers = append(numbers, 4, 5, 6)

    fmt.Println(numbers)
}
Output:[1 2 3 4 5 6]
GOLANG
Результат

Добавление одного среза в другой

Иногда нужно добавить не одно значение, а все элементы другого среза. Для этого используется ....

Main.go
package main

import "fmt"

func main() {
    first := []int{1, 2, 3}
    second := []int{4, 5, 6}

    first = append(first, second...)

    fmt.Println(first)
}
Output:[1 2 3 4 5 6]
GOLANG
Результат

Три точки ... раскрывают второй срез как набор отдельных элементов.

Оператор среза (s[i:j])

Оператор среза выглядит так: s[i:j], где:

  • s — исходный срез
  • i — начальный индекс (включительно)
  • j — конечный индекс (не включительно)
Индекс Значение
0 Almaty
1 Astana
2 New-York
3 Washington

Например, если написать cities[0:2], мы получим элементы с индексами 0 и 1. Элемент с индексом 2 уже не входит в результат.

Main.go
package main

import "fmt"

func main() {
    cities := []string{"Almaty", "Astana", "New-York", "Washington", "Paris", "Marcel"}

    kzCities := cities[0:2]
    usaCities := cities[2:4]
    frCities := cities[4:6]

    fmt.Println(kzCities)  // Almaty, Astana
    fmt.Println(usaCities) // New-York, Washington
    fmt.Println(frCities)  // Paris, Marcel
}
Output:[Almaty Astana] [New-York Washington] [Paris Marcel]
GOLANG
Результат

Короткие формы среза

В Go можно не указывать начальный или конечный индекс.

  • s[:3] — взять элементы от начала до индекса 3, не включая 3;
  • s[2:] — взять элементы от индекса 2 до конца;
  • s[:] — взять весь срез.
Main.go
package main

import "fmt"

func main() {
    numbers := []int{10, 20, 30, 40, 50}

    fmt.Println(numbers[:3])
    fmt.Println(numbers[2:])
    fmt.Println(numbers[:])
}
Output:[10 20 30] [30 40 50] [10 20 30 40 50]
GOLANG
Результат

Изменение элемента среза

Как и в массивах, элементы среза можно менять по индексу.

Main.go
package main

import "fmt"

func main() {
    cities := []string{"Almaty", "Astana", "Paris"}

    cities[2] = "London"

    fmt.Println(cities)
}
Output:[Almaty Astana London]
GOLANG
Результат

Здесь элемент с индексом 2 был заменён с Paris на London.

Удаление элемента

Удаление обычно делают комбинацией append и оператора среза. Мы берём элементы до индекса и элементы после индекса, затем "склеиваем" их.

Main.go
package main

import "fmt"

func main() {
    capitals := []string{"Astana", "Washington", "Marcel", "Paris"}

    num := 2 // удаляем элемент с индексом 2 (Marcel)
    capitals = append(capitals[:num], capitals[num+1:]...)
    fmt.Println(capitals)
}
Output:[Astana Washington Paris]
GOLANG
Результат

Важно: capitals[:num] — это элементы до num, а capitals[num+1:] — элементы после num. Три точки ... "раскрывают" срез как набор аргументов.

Как это работает:

  • capitals[:2] даёт [Astana Washington];
  • capitals[3:] даёт [Paris];
  • append соединяет эти части;
  • элемент Marcel пропадает из результата.

Перебор среза через range

Срезы удобно перебирать через range. Мы можем получить и индекс, и значение.

Main.go
package main

import "fmt"

func main() {
    cities := []string{"Almaty", "Astana", "Paris"}

    for index, value := range cities {
        fmt.Println(index, value)
    }
}
Output:0 Almaty 1 Astana 2 Paris
GOLANG
Результат

Если индекс не нужен

Если нужен только элемент, индекс можно заменить на _.

Main.go
package main

import "fmt"

func main() {
    cities := []string{"Almaty", "Astana", "Paris"}

    for _, value := range cities {
        fmt.Println(value)
    }
}
Output:Almaty Astana Paris
GOLANG
Результат

Пример: сумма элементов среза

Срезы часто используются вместе с циклами. Например, можно посчитать сумму всех чисел в срезе.

Main.go
package main

import "fmt"

func main() {
    numbers := []int{10, 20, 30, 40}
    sum := 0

    for _, value := range numbers {
        sum = sum + value
    }

    fmt.Println(sum)
}
Output:100
GOLANG
Результат

Пример: поиск максимального числа

С помощью цикла и среза можно найти максимальное число.

Main.go
package main

import "fmt"

func main() {
    numbers := []int{15, 90, 12, 45, 7}
    max := numbers[0]

    for _, value := range numbers {
        if value > max {
            max = value
        }
    }

    fmt.Println(max)
}
Output:90
GOLANG
Результат

Частые ошибки при работе со срезами

  • забыть сохранить результат append обратно в переменную;
  • обратиться к индексу, которого нет в срезе;
  • перепутать массив [5]int и срез []int;
  • забыть, что конечный индекс в s[i:j] не включается;
  • забыть поставить ..., когда добавляем один срез в другой.

Мини-практика

Чтобы лучше закрепить срезы, попробуйте написать программы для следующих задач:

  • создать срез из 5 чисел и вывести все элементы;
  • добавить в срез ещё несколько чисел через append;
  • вывести только первые 3 элемента среза;
  • вывести элементы с индекса 2 до конца;
  • удалить элемент по индексу;
  • посчитать сумму всех элементов;
  • найти максимальное число;
  • вывести только положительные числа.

Итоги

  • срез похож на массив, но имеет динамическую длину;
  • срез создаётся через []тип без указания размера;
  • make позволяет создать срез нужной длины;
  • append добавляет новые элементы;
  • s[i:j] позволяет получить часть среза;
  • конечный индекс в s[i:j] не включается;
  • элементы можно изменять по индексу;
  • удаление можно сделать через append и оператор среза;
  • range удобно использовать для перебора среза.

Оставить заявку

Оставьте контакты — наш отдел приёмной комиссии перезвонит и поможет выбрать курс.

Отправляя форму, вы соглашаетесь на связь от BITLAB Academy по вашей заявке.