День 10 · Контрольная точка 2: проверить программу с вводом · страница 2 из 3

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

Справочник по дням 06–09. Читать подряд не нужно — обязателен только блок «Попробуйте сейчас». Остальное открывайте, когда понадобится. Все сообщения — настоящие, Go 1.27.1.


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

Цель: в ~/errors.md не меньше двадцати разборов.

1. Недостающие сообщения получите сами: скопируйте selftest в черновик и ломайте способами из таблицы «Ошибки компилятора», по одному за раз. После каждой поломки — сборка:

▶ Выполните
cp ~/gocourse/day10/selftest/main.go ~/gocourse/day10/scratch/main.go
cd ~/gocourse/day10/scratch
go build .

2. Строка словарика — текст ошибки, тире, что это значило в вашем коде. Двоеточие вместо тире не засчитывается.

Готово, когда: пункт errors в course check 10 зелёный.


Команды

Команда Что делает День
./prog < input.txt ввод из файла 07
./prog > out.txt обычный вывод — в файл, поток ошибок — на экран 07
./prog 2> err.txt поток ошибок — в файл, обычный вывод — на экран 07
go run . < input.txt 2>/dev/null поток ошибок пропадает, на экране только результат 09
echo $? код возврата последней команды 07
go build -o prog . собрать под именем prog 07
Ctrl+D, Ctrl+C конец ввода с клавиатуры; остановить программу 07, 08
diff got.txt want.txt различия файлов; тишина — совпали 02, 10
for f in cases/*.txt; do …; done команды для каждого файла 10
dlv debug -r input.txt отладчик с вводом из файла 09

Конвейер: printf '3\n5\n' | ./prog — вывод printf становится вводом программы.

Цифра 2 в 2> — номер потока: у обычного вывода номер 1, и > — это сокращение от 1> (день 07, страница 5). /dev/null — особый файл: всё, что в него записано, пропадает (день 09, страница 2).

Команда dlv Что делает
break main.go:15 остановиться перед строкой 15
condition 1 boxes == 3 точка 1 срабатывает, только когда условие истинно
continue, next до следующей остановки; одна строка
step, stepout как next, но зайти внутрь вызываемой функции; досчитать её и вернуться туда, откуда её вызвали (день 09, страница 4)
print total, locals значение; все переменные функции
restart, exit начать заново; выйти

Условия — день 06

Код для чтения · разбираем, набирать не нужно
if weight > maxWeight {
	fmt.Println("Доставка невозможна")
} else if sum >= freeFrom {
	fmt.Println("Доставка: бесплатно")
} else {
	fmt.Println("Доставка платная")
}

switch zone {
case 1:
	fmt.Println("город")
case 2, 3:
	fmt.Println("область")
default:
	fmt.Println("нет доставки")
}
В условии задачи В коде
«больше N» x > N
«N или больше», «от N» x >= N
«до N включительно» x <= N
«меньше N» x < N

Срабатывает первая истинная ветка else if: узкое условие — раньше широкого. Правая часть && не вычисляется при ложной левой. Переменная из { } снаружи не видна.


Ввод и ошибки — день 07

Код для чтения · разбираем, набирать не нужно
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
qty, err := strconv.Atoi(strings.TrimSpace(scanner.Text()))
if err != nil {
	fmt.Fprintln(os.Stderr, "ошибка: не число")
	os.Exit(1)
}

Циклы — день 08

Код для чтения · разбираем, набирать не нужно
for i := 1; i <= n; i++ { }
for stock > 0 { }
for { if done { break } }
for scanner.Scan() { }
Заголовок Сколько раз тело
i := 0; i < n; i++ n
i := 1; i <= n; i++ n
i := 1; i < n; i++ n − 1
i := n; i > 0; i-- n

Накопитель объявляют до цикла. Минимум и максимум начинают с первого значения, а не с нуля. continue — к следующему проходу, break — выход.


Трассировка: правила 1–15

Правила копились с дня 02 и нумеруются сквозь весь курс. Здесь они собраны целиком — открывать три прошлые страницы не нужно. Это тот же список, по которому сверяется таблица в kt6 контрольной точки; новых правил контрольная не вводит.

Строки и значения (день 02, страница 4).

  1. Одна строка таблицы — одна выполненная строка кода внутри main, включая строки с печатью.
  2. Значения записываются после выполнения шага.
  3. Переменной ещё нет — прочерк -. Это не ноль.
  4. То, что шаг не трогал, переписывается из строки выше: пустых клеток не бывает.
  5. Правая часть считается по предыдущей строке таблицы.
  6. Номера строк — по исходному файлу программы, без ваших вставок с отладочной печатью.

Ветвления (день 06, страница 4).

  1. Строка с if или } else if — шаг; значения в ней те же, что строкой выше: условие только читает.
  2. Строки } else { и одинокая } — не шаги.
  3. Строки невыполненных веток в таблицу не попадают: номера идут с пропусками.
  4. После первой сработавшей ветки остальная цепочка — не шаги.

Циклы (день 08, страница 4).

  1. Строка for — шаг каждый раз, когда программа к ней приходит. В первый раз выполняются начальное значение и проверка, в следующие — третья часть (i++) и проверка; в таблицу идут значения после всего этого.
  2. Последний шаг со строкой for — тот, где условие ложно; он есть всегда, и переменная цикла на нём уже «за границей».
  3. После цикла переменной цикла нет — прочерк.
  4. Строки break и continue — шаги. Значения в них переписываются из строки выше. После continue следующий шаг — строка for, после break — первая строка после цикла.
  5. Шаги нумеруются подряд, номера строк повторяются. Самопроверка: строка for встречается на один раз больше, чем выполнилось тело.

В блоке 3 к этим правилам добавятся 16–24 — про вызовы функций; там их собирает памятка блока 3.


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

Сообщение Причина День
syntax error: cannot use assignment count = 0 as value = вместо == в условии 06
syntax error: unexpected keyword else, expected } else на новой строке после } 06
syntax error: unexpected newline, expected { after if clause { перенесена на следующую строку 06
non-boolean condition in if statement в условии не сравнение 06
invalid operation: weight > limit (mismatched types int and float64) сравнение int с float64 06
declared and not used: discount и undefined: discount объявлена внутри if, нужна после 06
duplicate case 1 (constant of type int) in expression switch два одинаковых case; ниже строка previous case 06
assignment mismatch: 1 variable but strconv.Atoi returns 2 values у Atoi два результата 07
declared and not used: err err не проверен 07
undefined: err было n, _ :=, а ниже if err != nil 07
cannot use scanner.Text() (value of type string) as int value in variable declaration строка кладётся в int без Atoi 07
undefined: bufio, undefined: os пакета нет в import 07
undefined: i переменная цикла после цикла 08
syntax error: unexpected :=, expected ) for (i := 0; …) со скобками 08
non-boolean condition in for statement for scanner.Scan { без скобок вызова 08
break is not in a loop, switch, or select break вне цикла 08
continue is not in a loop continue вне цикла 08

go vet: main.go:8:2: unreachable code — строки после return; main.go:9:2: fmt.Println does not take io.Writer but has first arg os.Stderr — Println вместо Fprintln. Строки после os.Exit go vet не замечает.

При запуске: panic: runtime error: integer divide by zero и код 2 — делитель оказался нулём; exit status 1 — строка go run о коде 1. Последнюю в словарик нести не нужно: это не сообщение компилятора, а строка самого go run, и проверка её не засчитывает.


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

Признак Дефект День
ровно на пороге ответ как ниже порога в сравнении перепутано строгое с нестрогим 06
почти всё попадает в одну ветку широкое условие else if стоит раньше узкого 06
на один проход больше или меньше граница цикла, счёт с 0 или с 1 08
итог равен последнему значению или нулю накопитель объявлен внутри цикла 08
минимум 0 при положительных числах начальное значение минимума 08
пустые строки посчитаны как данные счётчик увеличен раньше проверки, которая их пропускает 08
panic: … divide by zero на пустом вводе деление до проверки на пустоту 08
на числе с пробелами — ошибка ввода нет strings.TrimSpace 07
после сообщения об ошибке есть результат нет os.Exit(1) 07
при > out.txt сообщение попало в файл Println вместо Fprintln(os.Stderr, …) 07
доля или процент вышли меньше, чем должны, или нулём у целых порядок * и / меняет результат: посчитайте оба порядка на числе, которое не делится нацело 09
найдено последнее подходящее вместо первого нет break 09

Отладка — день 09

Воспроизвести (ввод, на котором неверно) → сузить (где значение впервые стало не таким) → гипотеза → проверка → починка → прогон всего набора. Отладочная печать — в поток ошибок и с подписью, перед сдачей её убирают:

Код для чтения · разбираем, набирать не нужно
fmt.Fprintln(os.Stderr, "отладка:", box, load)

Глагол %q печатает строку в кавычках: пробелы по краям и пустая строка становятся видны — "14 ", "" (день 09, страница 2). \n в конце нужен: Printf сам перевод строки не ставит.

Код для чтения · разбираем, набирать не нужно
fmt.Fprintf(os.Stderr, "отладка: строка %d %q\n", i, line)

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