День 05 · Контрольная точка 1: как решать задачу · страница 4 из 5

Памятка блока 1

Справочник по дням 01–04. Читать подряд не нужно. Обязательное на этой странице — только блок «Попробуйте сейчас» ниже. Остальное открывайте, когда понадобится: на контрольной точке, в следующих блоках, когда встретится незнакомое сообщение компилятора. Все выводы и сообщения в таблицах — настоящие, Go 1.27.


Попробуйте сейчас: словарик до десяти разборов.

Цель: в ~/errors.md не меньше десяти строк «текст ошибки — что это значило в вашем коде».

Доведите словарик ~/errors.md до десяти разборов. Сообщения, которых у вас в нём ещё нет, получите сами: скопируйте программу разминки в черновик и ломайте её способами из таблицы «Ошибки компилятора» ниже — по одному за раз. Копия заменит то, что лежит в черновике.

▶ Выполните
cp ~/gocourse/day05/warmup/main.go ~/gocourse/day05/scratch/main.go
cd ~/gocourse/day05/scratch
go run .

Каждое новое сообщение — строкой в ~/errors.md: текст ошибки, тире, что это значило в вашем коде. Двоеточие вместо тире не засчитывается: оно есть в каждом сообщении компилятора. Переписанная из таблицы колонка «что значит» памяти не оставляет.

Готово, когда: в ~/errors.md не меньше десяти строк, в каждой — текст ошибки, тире и разбор (пункт проверки errors).


Команды

Команда Что делает День
pwd, ls, ls -l где я; что в папке; подробно 01
cd папка, cd .., cd перейти; на уровень вверх; домой 01
mkdir папка, cat файл создать папку; напечатать файл 01
code . открыть текущую папку в VS Code 01
go run . собрать программу из текущей папки и сразу запустить 01
go build, ./имя собрать исполняемый файл; запустить его 01
gofmt -l ., gofmt -w main.go какие файлы не отформатированы; отформатировать 01
go vet . найти подозрительное, что пропускает компилятор 03
go doc strings.Repeat справка по функции пакета 04

Скелет программы

Код для чтения · разбираем, набирать не нужно
package main

import (
	"fmt"
	"strings"
)

func main() {
	// данные
	// расчёт
	// печать
}

Один пакет — import "fmt", несколько — в скобках, по строке на пакет. Подключённый и неиспользованный пакет — ошибка компиляции.


Переменные и присваивание — день 02

Запись Что делает
qty := 5 объявить переменную и присвоить значение; тип — по значению
var qty int объявить с нулевым значением: 0 у int, "" у string, 0 у float64, false у bool
qty = qty + 1 новое значение из старого; справа — значение до присваивания
qty += 3, qty -= 3 то же короче
qty++, qty-- плюс один, минус один
a, b = b, a обмен: обе правые части считаются до присваивания
const vat = 20 константа — менять нельзя
total := price * qty копия результата на момент выполнения, не формула

Имена: буквы, цифры, _, не с цифры; регистр важен. Внутри функции объявляют :=, снаружи — только var и const.


Типы и арифметика — день 03

Выражение Результат Почему
7 / 2 3 деление целых отбрасывает дробь
7 % 2 1 остаток от деления
7.0 / 2, float64(7) / 2 3.5 хотя бы одно дробное — деление дробное
int(f) при f := 3.99 3 дробь отбрасывается, не округляется
1205 / 100, 1205 % 100 12, 5 рубли и копейки из копеек
2 + 3*4, (2+3)*4 14, 20 порядок действий как в математике
50/12*12, 50*12/12 48, 50 где стоит деление, там и теряется дробь
float64(1) / 3 0.3333333333333333 дробные числа хранятся приближённо
"шт" + "." шт. склейка строк; строку с числом + не склеивает

Деньги — в копейках, в int. Считать целыми, печатать через fmt.Printf("%d.%02d руб.\n", sum/100, sum%100). Дробь вида 0,1 в двоичной памяти точно не записывается, и копейки начинают «плыть».


Printf — день 03

Одна строка со всеми глаголами:

Код для чтения · разбираем, набирать не нужно
fmt.Printf("%d|%s|%v|%T|%.2f|%02d|%%\n", 42, "шт", true, 3.5, 2.456, 5)
Вывод · это печатает программа, набирать не нужно
42|шт|true|float64|2.46|05|%
Глагол Что печатает
%d целое
%s строку
%v любое значение в обычном виде
%T тип значения
%.2f дробное с двумя знаками после точки, с округлением
%02d целое не короче двух цифр, с ведущим нулём
%% сам знак процента
\n перевод строки — Printf сам его не ставит

Готовые функции — день 04

Вызов Результат
strings.ToUpper("кабель usb") КАБЕЛЬ USB
strings.ToLower("SK-4471") sk-4471
strings.TrimSpace(" sk 4471 ") sk 4471 — пробелы по краям убраны
strings.ReplaceAll("sk 4471 b", " ", "-") sk-4471-b
strings.Repeat("=", 5) =====
strings.Contains("стретч-плёнка", "плёнка") true
strings.HasPrefix("SK-4471", "SK") true
strings.Count("a-b-c", "-") 2
len("кабель") 12 — байтов: кириллическая буква занимает два
utf8.RuneCountInString("кабель") 6 — символов; пакет unicode/utf8
strconv.Itoa(42) + " шт." 42 шт.
fmt.Sprintf("%d.%02d", 1205/100, 1205%100) 12.05 — строка, а не печать; из дополнительных материалов дня 04 (course extra 04)
math.Round(2.5), math.Floor(2.7), math.Ceil(2.1) 3, 2, 3 — все три возвращают float64
min(3, 7), max(3, 7) 3, 7; из дополнительных материалов дня 04 (course extra 04)

Функция возвращает результат — его надо записать в переменную или сразу передать дальше. Сама по себе она ничего не меняет.


Ошибки компилятора

Слева — текст после ./main.go:строка:колонка:.

Сообщение Что значит Как выглядит в коде Что делать
undefined: fmt.println (but have Println) не тот регистр fmt.println(...) fmt.Println
newline in string строка не закрыта кавычкой fmt.Println("Склад) закрыть кавычку
syntax error: unexpected EOF, expected } не закрыта фигурная скобка нет последней } закрыть
syntax error: unexpected semicolon or newline before { { перенесена на новую строку func main() и { ниже { на строке с func main()
syntax error: unexpected literal 7 in argument list; possibly missing comma or ) нет запятой между аргументами fmt.Println("Товаров:" 7) поставить запятую
"strings" imported and not used пакет подключён, но не нужен "strings" в import без вызовов убрать из import
undefined: strings пакет используется, но не подключён strings.ToUpper(...) без импорта добавить в import
declared and not used: reserved переменная объявлена и не используется reserved := 15, дальше ни разу использовать или удалить
no new variables on left side of := := для уже объявленной переменной total := total + 450 = вместо :=
undefined: totl такого имени нет — опечатка или не объявлено fmt.Println(totl) исправить имя
syntax error: non-declaration statement outside function body := вне функции limit := 100 над func main внутрь main или var limit = 100
cannot assign to vat (neither addressable nor a map index expression) присваивание константе const vat = 20, потом vat = 22 переменная вместо константы
cannot use "пять" (untyped string constant) as int value in assignment в переменную int кладут строку qty := 5, потом qty = "пять" значение того же типа
invalid operation: price * rate (mismatched types int and float64) действие над разными типами 4590 * 1.2 через переменные float64(price) * rate
invalid operation: "Остаток: " + total (mismatched types untyped string and int) строку склеивают с числом "Остаток: " + total Println("Остаток:", total) или strconv.Itoa(total)
cannot use 2.5 (untyped float constant) as int value in variable declaration (truncated) дробь в целую переменную var qty int = 2.5 целое значение или float64
1.2 (untyped float constant) truncated to int целое умножают на дробную константу total = total * 1.2 при total := 450 считать в float64 или целыми: total * 12 / 10
cannot convert 3.99 (untyped float constant) to type int int() от дробной константы int(3.99) от дробной переменной: int(f) при f := 3.99 даёт 3; константа без дроби, int(4.0), собирается
invalid operation: operator % not defined on kg (variable of type float64) остаток бывает только у целых kg % 2 при kg := 7.5 считать в целых: граммы, копейки
invalid operation: division by zero деление на ноль прямо в коде 10 / 0 исправить делитель
not enough arguments in call to strings.Repeat аргументов меньше, чем нужно; ниже have — что передали, want — что ждёт функция strings.Repeat("=") strings.Repeat("=", 5)
too many arguments in call to strconv.Itoa аргументов больше, чем нужно strconv.Itoa(5, 10) strconv.Itoa(5)
cannot use "3" (untyped string constant) as int value in argument to strings.Repeat аргумент не того типа strings.Repeat("=", "3") strings.Repeat("=", 3)
cannot use price (variable of type float64) as int value in argument to strconv.Itoa Itoa принимает только int strconv.Itoa(price) при price := 12.5 int(price) или fmt.Sprintf("%.2f", price) из course extra 04
cannot use math.Ceil(x) (value of type float64) as int value in variable declaration функции math возвращают float64 var boxes int = math.Ceil(x) int(math.Ceil(x))
len(name) (value of type int) is not used результат вызова выброшен строка len(name) сама по себе записать в переменную

Собирается, но не то

Компилятор молчит — ошибка видна только при запуске или через go vet.

Деление на ноль при запуске. Делитель — переменная, и ноль в ней компилятор не видит:

Пример · только посмотреть, набирать не нужно
stagiaire@lab:~/gocourse/day05/scratch$ go run .
panic: runtime error: integer divide by zero

goroutine 1 [running]:
main.main()
	/home/stagiaire/gocourse/day05/scratch/main.go:8 +0x9
exit status 2

Читать первую строку и main.go:8 — номер строки с делением.

Что видите Что это значит Что делать
Цена: %!d(float64=12.5) руб.; go vet: fmt.Printf format %d has arg price of wrong type float64 глагол не подходит к типу %.2f для дробных, %d для целых
%!d(MISSING) шт.; go vet: fmt.Printf format %d reads arg #1, but call has 0 args в Printf глагол есть, значения нет передать значение после строки формата
строка не стала заглавной, компилятор и go vet молчат strings.ToUpper(name) без присваивания name = strings.ToUpper(name)
12 вместо 6 символов len считает байты utf8.RuneCountInString
процент или доля — 0 целые поделены раньше, чем умножены: дробь отбросилась сразу, и до умножения дошёл ноль умножать до деления, а не после
переменная «не обновилась» присваивание скопировало старое значение пересчитать после изменения
два числа в выводе поменялись местами аргументы Printf не в том порядке, что глаголы сверить глаголы и аргументы по порядку

Дальше: правила контрольной точки — course next