День 04 · Чужой код и готовые функции · страница 1 из 7

Вызов функции

Сегодня день чтения: чужой код читают чаще, чем пишут свой с нуля, и большая часть этого кода — вызовы готовых функций. Свои функции будете писать в день 11.


Функция — готовое действие с именем

Одну функцию вы уже вызывали — fmt.Println. Функция — кусок кода, который кто-то написал заранее и назвал: чтобы им пользоваться, надо знать только имя, что передать и что она вернёт. func main — тоже функция, только её вызывает Go сам при запуске программы.


Ситуация: артикул большими буквами

В выгрузке поставщика артикулы записаны маленькими буквами: tk-4821, а на этикетке нужно TK-4821, и артикулов тысячи. В пакете strings есть ToUpper — «в верхний регистр».

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

import (
	"fmt"
	"strings"
)

func main() {
	sku := "tk-4821"
	code := strings.ToUpper(sku)
	fmt.Println("Артикул:", code)
	fmt.Println(strings.Repeat("=", 16))
	fmt.Println(sku)
}

Пакетов теперь два, поэтому import со скобками — подробнее на следующей странице.

Что увидите:

Пример · только посмотреть, набирать не нужно
stagiaire@lab:~/gocourse/day04/scratch$ go run .
Артикул: TK-4821
================
tk-4821

Как это читать

Разберём строку code := strings.ToUpper(sku):

Кусок Что значит
strings пакет, где живёт функция; он подключён в import
. «из пакета strings взять…»
ToUpper имя функции. С большой буквы — значит, её можно вызывать из другого пакета
(sku) аргумент — что передаём функции
code := результат вызова кладём в новую переменную

Сначала Go вычисляет аргумент, потом уходит в функцию и возвращается с результатом. Результат встаёт на место вызова — как будто написано code := "TK-4821".

Последняя строка вывода — tk-4821: переменная sku не изменилась. ToUpper не переделывает строку, а возвращает новую. Нужен результат — положите его в переменную, можно в ту же: sku = strings.ToUpper(sku).

strings.Repeat("=", 16) — вызов с двумя аргументами через запятую: что повторять и сколько раз. Как узнать их порядок, не гадая, — на пятой странице.


Результат можно сразу передать дальше

Вызов можно поставить везде, где подходит значение такого типа, — даже в аргумент другого вызова.

Дальше показываем только строки из тела main — вставляйте их между { и } в scratch/main.go. С одним import "fmt" первая строка тела — шестая. Пакеты, которые вызывает фрагмент, добавьте в import сами: Ctrl+S их не добавляет.

Код для чтения · разбираем, набирать не нужно
raw := "  tk-4821 "
fmt.Println("[" + strings.ToUpper(strings.TrimSpace(raw)) + "]")
Вывод · это печатает программа, набирать не нужно
[TK-4821]

Вложенные вызовы читаются изнутри наружу: TrimSpace даёт "tk-4821", ToUpper — "TK-4821", потом склейка, потом печать.

Попробуйте сейчас: вложенные вызовы в черновике.

Цель: увидеть, что вложенные вызовы выполняются изнутри наружу.

Наберите в черновике программу целиком — те же две строки тела main, а import со скобками:

✎ Наберите в файл scratch/main.go
package main

import (
	"fmt"
	"strings"
)

func main() {
	raw := "  tk-4821 "
	fmt.Println("[" + strings.ToUpper(strings.TrimSpace(raw)) + "]")
}
▶ Выполните
cd ~/gocourse/day04/scratch
go run .

Должно напечататься [TK-4821]. Потом уберите внутренний вызов: вместо strings.TrimSpace(raw) оставьте просто raw. Предскажите, где окажутся пробелы в скобках, и проверьте запуском.

После опыта верните черновик к заготовке — package main, import "fmt", в теле main одна строка fmt.Println("черновик"): номера строк в следующих фрагментах считаются от неё.

Готово, когда: первый запуск напечатал [TK-4821], предсказание пробелов сверено со вторым запуском, а черновик снова заготовка с одним "fmt" в import.


Одни функции делают, другие отвечают

fmt.Println делает: печатает на экран. strings.ToUpper ничего не печатает и не меняет — только отвечает значением. Ответ, который никуда не положили, пропадает:

Код для чтения · разбираем, набирать не нужно
sku := "tk-4821"
strings.ToUpper(sku)
fmt.Println(sku)
Вывод · это печатает программа, набирать не нужно
tk-4821

Компилятор здесь молчит: вызвать функцию и выбросить результат в Go разрешено. Программа собирается и печатает не то — ошибку видно только по выводу. Это главная ловушка дня: она встретится и в label, и в fix2.

К встроенным функциям вроде len компилятор строже: строка len(sku) сама по себе не соберётся. Поставьте её вместо strings.ToUpper(sku) — пакет strings больше не вызывается, в import остаётся один "fmt":

Вывод · это печатает программа, набирать не нужно
./main.go:7:2: len(sku) (value of type int) is not used

У strings.ToUpper выброшенный результат не поймает никто, кроме вас.

Бывают и функции с двумя результатами: strings.CutPrefix отрезает начало строки и сообщает, было ли это начало, — слева тогда две переменные через запятую. Пример в course extra 04, подробно — в день 07.


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

Аргументов меньше, чем нужно — в программе из «Ситуации» из вызова strings.Repeat убрали , 16:

Вывод · это печатает программа, набирать не нужно
./main.go:12:29: not enough arguments in call to strings.Repeat
	have (string)
	want (string, int)

have — что вы передали, want — что функция ждёт.

Что видите Что это значит Что делать
not enough arguments in call to strings.Repeat аргументов меньше, чем принимает функция добавить недостающие — типы и порядок в строке want
too many arguments in call to strings.ToUpper, ниже have (string, string), want (string) передан лишний аргумент убрать лишнее
cannot use 16 (untyped int constant) as string value in argument to strings.Repeat и сразу cannot use "=" (untyped string constant) as int value ... аргументы переставлены местами порядок — как в go doc strings.Repeat
программа собирается, но строка не поменялась результат ToUpper выброшен молча sku = strings.ToUpper(sku)

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

Цель: увидеть сообщения о числе и порядке аргументов и молча выброшенный результат, а сами сообщения записать в словарик.

Откройте папку дня в VS Code и наберите в черновик программу из «Ситуации»:

▶ Выполните
cd ~/gocourse/day04
code .
✎ Наберите в файл scratch/main.go
package main

import (
	"fmt"
	"strings"
)

func main() {
	sku := "tk-4821"
	code := strings.ToUpper(sku)
	fmt.Println("Артикул:", code)
	fmt.Println(strings.Repeat("=", 16))
	fmt.Println(sku)
}
▶ Выполните
cd ~/gocourse/day04/scratch
go run .

Вывод — как в «Что увидите». Потом по очереди, каждый раз запуская go run . и возвращая как было:

  1. Уберите , 16 из strings.Repeat. Прочитайте have и want.
  2. Поменяйте аргументы местами: strings.Repeat(16, "="). Сообщений будет два — на каждый аргумент.
  3. Замените code := strings.ToUpper(sku) на strings.ToUpper(sku), а в первом Println вместо code напечатайте sku. Компилятор промолчит — посмотрите, что напечатается.

Новые сообщения запишите в ~/errors.md, как в день 01: слева текст ошибки, тире, справа — что это значило.

Готово, когда: на шаге 1 вы видели not enough arguments… с have и want, на шаге 2 — два cannot use …, на шаге 3 программа напечатала Артикул: tk-4821, а новые сообщения — в ~/errors.md (пункт errors).


Попробуйте сейчас: что выведет, не запуская.

Цель: предсказать вывод по коду и отправить его.

Не запуская, предскажите вывод:

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

import (
	"fmt"
	"strings"
)

func main() {
	sku := "tk-4821"
	strings.ToUpper(sku)
	fmt.Println(sku, strings.Repeat("ab", 3))
}

Отправьте предсказанную строку целиком:

▶ Выполните · выделенное замените своим
course answer day04.q1 ВАШ_ОТВЕТ

Потом проверьте себя запуском — ту же программу в черновик:

✎ Наберите в файл scratch/main.go
package main

import (
	"fmt"
	"strings"
)

func main() {
	sku := "tk-4821"
	strings.ToUpper(sku)
	fmt.Println(sku, strings.Repeat("ab", 3))
}
▶ Выполните
cd ~/gocourse/day04/scratch
go run .

Разошлось — отправьте ответ заново, засчитывается последний.

Готово, когда: course answer ответил Принято: day04.q1 = …, а вывод совпал с отправленной строкой (пункт проверки q1).


Дальше: пакет strings — course next