Отладчик 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$Как это читать. По порядку.
Type 'help' for list of commands.и приглашение(dlv)— отладчик ждёт команду. Программа собрана, но доmainещё не дошла.break main.go:25— точка останова на строке 25. Ответ: точка номер 1 поставлена. Адрес0x4b9949можно не читать, у вас он может быть другим.continue— выполнять программу до ближайшей точки. Отладчик показывает, где остановился, и код вокруг. Стрелка=>— строка, которая будет выполнена следующей, но ещё не выполнена.total:1в скобках — сколько раз программа дошла до этой точки.print qty—12: строка 20 уже выполнилась.print total—0: строка 25 ещё нет.next— выполнить текущую строку и остановиться на следующей. Следующей оказалась 17 — заголовок цикла, начало нового прохода. Теперьtotalравен 12.- Второй
continue— второй проход дошёл до строки 25,total:2.iравен 2,total— 12: вторая коробка ещё не прибавлена. locals— все переменные функции разом.scannerпоказан адресом в памяти: так отладчик показывает значения этого вида, читать его не нужно — у вас на месте0x…будет своё число.err = error nil— ошибки нет.exit— выйти. Программа останавливается вместе с отладчиком.
Команды и их короткие имена:
| Команда | Коротко | Что делает |
|---|---|---|
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.txt2. Повторите сеанс выше у себя — после
(dlv)по одной команде:▶ Выполните в отладчике · по одной команде в ответ на (dlv), не в оболочкуbreak main.go:25 continue print qty print total next print total continue print total print i locals exit3. Затем новый сеанс: точка на строке 25 и
continueчетыре раза подряд. До того как набрать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 exit4. Сверьте предсказание с тем, что показал отладчик. Не сошлось — посчитайте остановки заново:
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