День 09 · Отладчик и поиск ошибок · страница 3 из 6

Отладчик dlv

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

Отладчик Go называется Delve, команда — dlv. Он уже установлен:

Пример · только посмотреть, набирать не нужно
stagiaire@lab:~$ dlv version
Delve Debugger
Version: 1.27.2
Build: $Id: 360e7b2181d3da54115aaee4f569954bca95cfe3 $

Как подать программе ввод

Ситуация. priemka читает накладную из ввода. С go run вы пишете < input.txt. С отладчиком так нельзя: dlv сам читает с клавиатуры — ваши команды. Стрелка < отняла бы у него клавиатуру, и он отказывается:

Пример · только посмотреть, набирать не нужно
stagiaire@lab:~/gocourse/day09/priemka$ dlv debug < input.txt
Stdin is not a terminal, use '-r' to specify redirects for the target process or --allow-non-terminal-interactive=true if you really want to specify a redirect for Delve

Сообщение называет правильный способ — ключ -r, «перенаправить ввод программы». Клавиатура остаётся у отладчика, а программа читает файл:

Пример · только посмотреть, набирать не нужно
stagiaire@lab:~/gocourse/day09/priemka$ dlv debug -r input.txt

Полная запись того же — --redirect stdin:input.txt. Второй ключ из сообщения, --allow-non-terminal-interactive, вам не нужен: он для скриптов, которые сами подают команды отладчику.

dlv debug собирает программу из текущего каталога — как go run ., но так, чтобы отладчик видел переменные и строки, — запускает её и останавливает до первой строки main.


Первый сеанс

Верните priemka к оригиналу — номера строк ниже по нему:

Пример · только посмотреть, набирать не нужно
stagiaire@lab:~$ cd ~/gocourse/day09/priemka
stagiaire@lab:~/gocourse/day09/priemka$ cp ~/.course/orig/day09/priemka/main.go .

Что увидите. Сеанс целиком: после (dlv) — то, что набрано.

Пример · только посмотреть, набирать не нужно
stagiaire@lab:~/gocourse/day09/priemka$ dlv debug -r input.txt
Type 'help' for list of commands.
(dlv) break main.go:25
Breakpoint 1 set at 0x4b9949 for main.main() ./main.go:25
(dlv) continue
> [Breakpoint 1] main.main() ./main.go:25 (hits goroutine(1):1 total:1) (PC: 0x4b9949)
    20:			qty, err := strconv.Atoi(line)
    21:			if err != nil {
    22:				continue
    23:			}
    24:			boxes++
=>  25:			total += qty
    26:		}
    27:		fmt.Println("Коробок:", boxes)
    28:		fmt.Println("Штук:", total)
    29:	}
(dlv) print qty
12
(dlv) print total
0
(dlv) next
> main.main() ./main.go:17 (PC: 0x4b98b2)
    12:	func main() {
    13:		scanner := bufio.NewScanner(os.Stdin)
    14:		boxes := 0
    15:		total := 0
    16:		i := 0
=>  17:		for scanner.Scan() {
    18:			i++
    19:			line := scanner.Text()
    20:			qty, err := strconv.Atoi(line)
    21:			if err != nil {
    22:				continue
(dlv) print total
12
(dlv) continue
> [Breakpoint 1] main.main() ./main.go:25 (hits goroutine(1):2 total:2) (PC: 0x4b9949)
    20:			qty, err := strconv.Atoi(line)
    21:			if err != nil {
    22:				continue
    23:			}
    24:			boxes++
=>  25:			total += qty
    26:		}
    27:		fmt.Println("Коробок:", boxes)
    28:		fmt.Println("Штук:", total)
    29:	}
(dlv) print total
12
(dlv) print i
2
(dlv) locals
scanner = (*bufio.Scanner)(0x…)
boxes = 2
total = 12
i = 2
line = "8"
err = error nil
qty = 8
(dlv) exit
stagiaire@lab:~/gocourse/day09/priemka$

Как это читать. По порядку.

Команды и их короткие имена:

Команда Коротко Что делает
break main.go:N b поставить точку останова на строке N
continue c выполнять до ближайшей точки или до конца программы
next n выполнить текущую строку и остановиться на следующей
step s как next, но зайти внутрь вызываемой функции — страница 4
print x p показать значение переменной или выражения
locals — показать все переменные функции
breakpoints bp список точек останова
clear N — убрать точку номер N
exit quit, q выйти из отладчика

Всё, что набрано после (dlv), в журнал команд курса не попадает — туда попадёт одна строка dlv debug -r input.txt. Проверка засчитывает её, а что вы увидели внутри отладчика, покажут ответы на вопросы.


Попробуйте сейчас: сеанс dlv у себя.

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

1. Верните priemka к оригиналу и запустите отладчик:

▶ Выполните
cd ~/gocourse/day09/priemka
cp ~/.course/orig/day09/priemka/main.go .
dlv debug -r input.txt

2. Повторите сеанс выше у себя — после (dlv) по одной команде:

▶ Выполните в отладчике · по одной команде в ответ на (dlv), не в оболочку
break main.go:25
continue
print qty
print total
next
print total
continue
print total
print i
locals
exit

3. Затем новый сеанс: точка на строке 25 и continue четыре раза подряд. До того как набрать print, предскажите по input.txt и таблице ожиданий со страницы 1: что покажут print total и print i на четвёртой остановке? Подсказка к предсказанию: до строки 25 доходят не все строки ввода.

▶ Выполните
dlv debug -r input.txt

После (dlv):

▶ Выполните в отладчике · по одной команде в ответ на (dlv), не в оболочку
break main.go:25
continue
continue
continue
continue
print total
print i
exit

4. Сверьте предсказание с тем, что показал отладчик. Не сошлось — посчитайте остановки заново: hits ... total:N в строке остановки говорит, какая она по счёту.

Готово, когда: на первой остановке print qty показал 12, как в сеансе выше, предсказание для четвёртой остановки сверено, а пункты t_dlv и t_redirect в course check 09 зелёные.


Что может пойти не так

Ошибки сеанса отладчик печатает после Command failed: и остаётся в приглашении (dlv) — выходить не нужно.

Что видите Что это значит Что делать
Stdin is not a terminal, use '-r' to specify redirects ... ввод подан стрелкой < dlv debug -r input.txt
could not launch process: open input.text: no such file or directory опечатка в имени файла после -r ls — точное имя
# day09/priemka, строки компилятора и exit status 1 программа не собирается, отладчику нечего запускать чините ошибку компиляции, как в блоке 1
Command failed: could not find statement at /home/stagiaire/gocourse/day09/priemka/main.go:11, please use a line with a statement на строке 11 нет кода: пустая строка, одна скобка или комментарий точку — на строку с командой
Command failed: could not find symbol value for total до первого continue программа ещё не вошла в main, переменных пока нет сначала break и continue
Command failed: could not find symbol value for qty на остановке у строки 20 переменная объявляется на строке со стрелкой =>, а она ещё не выполнена next, потом print
Command failed: could not find symbol value for x такой переменной нет — опечатка в имени locals — какие есть
Command failed: not enough arguments в ответ на clear в dlv clear — не очистка экрана, а «убрать точку останова», ему нужен номер точки точки остались на месте; очистить экран — Ctrl+L
Process 1154765 has exited with status 0 в ответ на next или print программа уже закончилась: continue не встретил точек и дошёл до конца restart — страница 4 — или exit

Дальше: условия, шаг внутрь, перезапуск — course next