Перейти к содержимому

Практика 5. Массивы и базовая работа со slices

Цель

Научиться создавать массивы и slices, обращаться к элементам, использовать границы среза, len, range, make и базовый append, а также понимать различие между копированием массива и общим хранилищем slices.

Общие требования

  • создайте модуль example.com/practice-05;
  • перед обращением по вычисляемому индексу проверяйте границы;
  • функции обработки данных возвращают результат и не печатают его;
  • все примеры должны работать на Linux, macOS и Windows;
  • выполните go fmt ./..., go test ./..., go vet ./....

A. Разминка

Задание 1. Массив недели

Создайте массив [7]string с названиями дней недели. Выведите:

  • весь массив;
  • первый и последний день;
  • длину;
  • каждый день с номером от 1 до 7.

Используйте range для обхода.

Задание 2. Zero values массива

Объявите:

var measurements [5]float64

Выведите массив до и после заполнения трёх элементов. Объясните, почему остальные элементы равны нулю.

Задание 3. Копирование массива

first := [3]int{10, 20, 30}
second := first
second[0] = 999

Выведите оба массива. Объясните, почему изменение second не изменило first.

Создайте функцию:

func changeArray(values [3]int) [3]int

Она меняет первый элемент копии и возвращает новый массив.

Задание 4. Первый slice

Создайте:

languages := []string{"Go", "Python", "Swift", "Java", "C#"}

Получите и выведите:

  • первые два элемента;
  • последние три;
  • элементы с индексами 1–3;
  • весь slice через [:].

Для каждого результата выведите len и cap.


B. Основные задания

Задание 5. Сумма, минимум и максимум

Реализуйте:

func sum(values []int) int
func minMax(values []int) (minimum int, maximum int, ok bool)

Для пустого slice minMax возвращает 0, 0, false. Для непустого нельзя инициализировать минимум произвольным большим числом: используйте первый элемент.

Проверьте:

  • положительные числа;
  • отрицательные числа;
  • один элемент;
  • пустой slice.

Задание 6. Поиск элемента

Напишите:

func indexOf(values []string, target string) int

Функция возвращает индекс первого совпадения или -1. Сравнение регистрозависимое.

Дополнительный вариант:

func indexOfFold(values []string, target string) int

Используйте strings.EqualFold для поиска без учёта регистра.

Задание 7. Разворот

Реализуйте два варианта:

func reversed(values []int) []int
func reverseInPlace(values []int)
  • reversed возвращает новый slice и не изменяет исходный;
  • reverseInPlace изменяет переданный slice.

Покажите разницу в main.

Задание 8. Фильтрация

Напишите:

func validScores(scores []int) []int

Оставьте только значения от 0 до 100. Результат должен быть новым slice, а исходные данные — остаться без изменений.

Предварительно выделите вместимость результата:

result := make([]int, 0, len(scores))

Задание 9. Матрица

Создайте таблицу 3×4 как [][]int, заполните её числами от 1 до 12 и выведите по строкам.

Затем вычислите:

  • сумму каждой строки;
  • сумму каждого столбца;
  • сумму всех элементов.

Не предполагайте длину строки без проверки, если разрешите строки разной длины.


C. Проект «Список задач»

В этой работе названия задач хранятся в slice:

tasks := []string{
"Подготовить отчёт",
"Проверить почту",
"Исправить ошибку",
}

Реализуйте функции:

func addTask(tasks []string, title string) ([]string, bool)
func findTask(tasks []string, title string) int
func printTasks(tasks []string)

Требования:

  • addTask удаляет пробелы по краям через strings.TrimSpace;
  • пустое название не добавляется;
  • дубликат без учёта регистра не добавляется;
  • функция возвращает новый slice и признак успеха;
  • findTask ищет без учёта регистра;
  • нумерация при выводе начинается с 1;
  • пустой список выводится как Список задач пуст.

Сценарий:

  1. выведите начальный список;
  2. добавьте корректную задачу;
  3. попробуйте добавить пустое название;
  4. попробуйте добавить дубликат в другом регистре;
  5. найдите существующую задачу;
  6. найдите отсутствующую задачу;
  7. выведите итоговый список.

Пример:

1. Подготовить отчёт
2. Проверить почту
3. Исправить ошибку
Добавлено: Обновить документацию
Не добавлено: пустое название
Не добавлено: задача уже существует
Итоговый список:
1. Подготовить отчёт
2. Проверить почту
3. Исправить ошибку
4. Обновить документацию

Важно: addTask должна возвращать результат append, а вызывающая сторона — присваивать его обратно:

tasks, added = addTask(tasks, title)

Дополнительные задания

Сдвиг влево

Напишите функцию, возвращающую новый slice, циклически сдвинутый на один элемент:

[1 2 3 4] → [2 3 4 1]

Пустой slice и slice из одного элемента должны обрабатываться корректно.

Удаление повторов

Без использования map создайте функцию, сохраняющую только первое появление каждой строки. Сравнивайте строки без учёта регистра. Оцените сложность решения.

Критерии оценивания

КритерийБаллы
Массивы и понимание копирования0–3
Срезы, len, cap, границы0–3
Функции поиска и статистики0–3
Фильтрация и независимый результат0–3
Проект «Список задач»0–4
Максимум16

Вопросы для защиты

  1. Почему длина массива входит в его тип?
  2. Что происходит при присваивании массива?
  3. Чем литерал массива отличается от литерала slice?
  4. Что означают левая и правая границы среза?
  5. Чем len отличается от cap?
  6. Почему результат append нужно присваивать?
  7. Как изменить элементы slice через range?
  8. Почему minMax должен отдельно обрабатывать пустой slice?