Это статья об основах программирования на Go. На канале я рассказываю об опыте перехода в IT с нуля, структурирую информацию и делюсь мнением.
Хой, джедаи и амазонки! Выполнил очередную практику и получил такой комментарий от куратора:
Что тут скажешь - куратор немногословен) А много слов и ни к чему, если работа отличная (сам себя не похвалишь, как говорится, никто не похвалит).
Сегодня разберу, что хорошего было в коде, какие были альтернативы и для чего может быть полезен код по поиску символов в строках. И всё это заправлено техническими примочками, в частности - матрицей. Go разбираться!
1. Назначение кода по поиску символов
Я не вдавался в подробности, для чего на практике может применяться подобный код. Вот что мне подсказывает логика нейросеть:
Код, который ищет символы в строках, может быть полезен для решения разных задач в программировании. Например:
- Валидация ввода пользователя: при разработке приложений пользователи могут вводить данные, которые не соответствуют заданным форматам. Например, при регистрации пользователей нужно проверять, что введенный email имеет правильный формат. Для этого можно написать код, который ищет символ "@" в строке, введенной пользователем.
- Обработка текстовых данных: в программировании часто приходится работать с текстовыми данными. Например, нужно найти все вхождения определенного слова в тексте или заменить все вхождения одного символа на другой.
- Работа с файлами: при чтении файлов в программе нужно уметь искать нужные строки или определенные символы в строках.
- Работа с API: при работе с API (Application Programming Interface) часто нужно искать определенные символы в ответе от сервера.
В общем, код, который ищет символы в строках, может быть полезен для решения многих задач в программировании, связанных с обработкой текстовых данных и взаимодействием с пользователем или внешними источниками данных.
2. Задача и ход решения
2.1. Описание задачи
Есть несколько мудрёное задание:
Напишите функцию, которая на вход принимает массив предложений (длинных строк) и массив символов типа rune, а возвращает 2D-массив, где на позиции [i][j] стоит индекс вхождения символа j из chars в последнее слово в предложении i (строку надо разбить на слова и взять последнее).
Далее посмотрим результат работы моей программы, чтобы было понятнее что нужно и как это может выглядеть.
2.2. Вывод в терминал
И продолжение вывода информации в терминал:
Какая здесь была альтернатива вывода? Во-первых, не обязательно печатать промежуточные результаты заполнения массивов. Не обязательно отделять пустыми строками смысловые блоки текста. Не обязательно форматировать вывод массивов и матриц, а использовать обычный Println без обходов, который бы выдал что-то такое в терминал: [А, и, И, р]. Но это всё ухудшает визуальное восприятие, поэтому полезнее всё это оставить.
Далее расскажу, что здесь ещё интересного.
2.3. Особенности решения
Ход решения следующий:
- Создаём срез строк и заполняем элементы среза фразами.
- В каждом элементе среза строк оставляем последнее предложение из всей фразы.
- Создаём матрицу, число рядов в которой равно количеству элементов среза строк; а количество столбцов равно количеству рун;
- Ищем индексы символов в элементах среза строк и одновременно заполняем матрицу.
В итоге мы печатаем матрицу, а не просто строки. Как всё это выглядит в коде?
3. Разбор кода
Сам код можно посмотреть на моём GitHub'e.
Помимо хода решения, код разбит на маленькие функции для удобства чтения и редактирования - именно за это работу похвалил куратор. А также, думаю, за говорящие имена переменных и функций.
Код состоит из 141 строки, 15 функций и 4 пакетов: bufio, fmt, os, strings.
Альтернативой было бы сделать меньше функций, или вообще - всё запихнуть в одну main. Однако это сделало бы код менее читаемым - что в перспективе на более сложных и реальных проектах усложнит работу команде разработчиков при поддержке кода.
3.1. Основные функции
Я придерживался правила чистого кода, в котором говорится: хорошая функция - короткая функция. Пусть ваши функции будут не более 15 строк.
Для этого я разбил функцию main на три смысловых элемента, каждый из которых не более 15 строк - но если их объединить вместе, будет больше 15:
Считается, что хорошему коду не требуются комментарии - сам код говорит за себя. С другой стороны, для кода пишется документация. Попробую я написать её здесь:
- В 11й строке мы видим просто вывод в терминал заголовка программы.
- В 12й я создаю два среза.
- В 13й создаю матрицу с требуемой информацией.
Всё - это функция main. Очень короткая, а следующие две функции идут по порядку от функции main - т.е., я располагаю последующие функции в том порядке, в котором они появляются в программе.
Хотя нет никакой сложности в навигации между функциями: щёлкаем через Ctrl по функции, и наша IDE переносит нас в то место, где находится эта функция.
Что ещё из интересного - в строке 31 я инициализирую переменные для размеров матрицы. Этого можно было бы и не делать - просто использовать функцию len при создании и обработке матрицы, но я посчитал такой ход полезным и упрощающим чтение кода.
3.2. Срез строк
Далее я создаю срез строк
А также обрезаю фразы до последнего предложения:
И печатаю срез:
Что здесь интересного?
В строках 52-56 я считываю фразы целиком. Т.е. использую не привычный fmt.Scan(&answer), который считывает символы до пробела. А более продвинутую версию.
Также при выводе текста в терминал, например в строке 61, я в начале использовал управляющий символ \n переноса строки - для визуального отделения в терминале информации (интервал, отделяющий текст от предыдущего текстового блока).
3.3. Срез рун
Срез рун аналогичен срезу строк - всё примерно то же самое:
Что здесь отмечу - пришлось повозиться с выводом руны в терминал. Для этого использовал спецификатор %c.
Ещё использовал управляющий символ табуляции \t для красивого вывода символов в терминал.
Да, вот ещё - 79я строка позволяет нам считывать только первый символ. Например, если мы введём несколько символов - то последующие будут отброшены.
3.4. Матрица
Далее мы создаём матрицу (о матрицах я писал здесь <<<).
оздать пустую матрицу с заданными размерами и значениями элементов матрицы по-умолчанию - не такая уж простая задача. Это делается через цикл:
Далее мы сопоставляем руны (символы) с имеющимися строками и заполняем матрицу информацией:
Что здесь интересного: в строке 126 я использовал функцию Sprintf. Это аналог функции Printf - только не для вывода информации в терминал, а для создания "сложной" строки, состоящей из текста и внедрённых в неё спецификаторов.
4. Выводы
Это была одна из самых сложных моих практических работ. Я выполнял её блоками и проверял работоспособность на этапе разработки каждой функции.
Для меня это большой код, я доволен что постепенно учусь писать всё более сложные программы, понимать что от меня хотят по "невнятному" ТЗ, а также кайфовать от разработки и поиска недостающей информации.
Успехов, Бро!
--//--//--
Если захочешь купить курс от SkillBox, воспользуйся моей реферальной ссылке: ты получишь огромную скидку на курс и плюс в карму за помощь каналу. Хотя на данный момент (май 2023), курс Go-разработчик от SkillBox снят с продаж.
Бро, ты уже здесь? 👉 Подпишись на канал для новичков «Войти в IT» в Telegram, будем изучать IT вместе 👨💻👩💻👨💻