День 03 — глубже
Всё здесь необязательно. Материалы на английском помечены. Первые три раздела — продолжение страниц дня: то, что в них не влезло.
Нулевые значения
Переменная, объявленная через var без значения, получает нулевое значение своего типа:
var a int
var b float64
var c string
var d bool
fmt.Println(a, b, c, d)0 0 falseМежду 0 и false два пробела: там напечатана пустая строка "", а Println поставил пробелы до неё и после. Нулевые значения ещё понадобятся в дне 06, когда появятся условия: переменная без значения там не «пустая», а вполне определённая.
Почему int(3.99) не компилируется, а int(4.0) — да
Число, записанное прямо в коде, — константа без типа. Компилятор знает её значение заранее и подгоняет под тип соседа: если при этом ничего не теряется (4.0 → 4, var w float64 = 3 → 3.0), он молча соглашается; если теряется дробь (int(3.99), x * 2.5 при целом x, var qty int = 12.5), отказывается собирать программу. Значение переменной известно только при работе, поэтому там компилятор ничего не решает: int(w) — ваше явное разрешение отбросить дробь, а float64(x) — явное разрешение расширить целое.
Из той же логики ещё три сообщения дня — они попадаются, когда тип переменной и тип значения не сходятся:
| Что видите | Что это значит | Что делать |
|---|---|---|
cannot use weight * 4 (value of type float64) as int value in variable declaration |
дробный результат кладёте в переменную int |
переменная float64 или int(weight * 4) |
cannot use count (variable of type int) as float64 value in variable declaration |
целую переменную кладёте в дробную | float64(count) |
x / 2.0 печатает целое |
2.0 подогнано под int соседа |
float64(x) / 2 |
Ещё три находки go vet
К двум сообщениям с четвёртой страницы — те, что встречаются чаще всего:
| Код | Что напечатает | Что скажет go vet . |
|---|---|---|
fmt.Printf("Итого: %d\n") |
Итого: %!d(MISSING) |
fmt.Printf format %d reads arg #1, but call has 0 args |
fmt.Printf("Итого: %d руб. %02d коп.\n", 123) |
Итого: 123 руб. %!d(MISSING) коп. |
fmt.Printf format %02d reads arg #2, but call has 1 arg |
fmt.Printf("Итого: %d\n", 5, 7) |
Итого: 5, на следующей строке %!(EXTRA int=7) |
fmt.Printf call needs 1 arg but has 2 args |
Тур по Go: типы и константы (англ.)
- Basic types — https://go.dev/tour/basics/11 Все встроенные типы списком: кроме
intиfloat64естьint8,uint,float32и другие. В курсе до блока 4 хватает четырёх из сегодняшнего дня. - Type conversions — https://go.dev/tour/basics/13 Преобразования
float64(x)иint(f)— то же, что на третьей странице. - Numeric Constants — https://go.dev/tour/basics/16 Почему константа в коде может быть огромной, пока её не положили в переменную.
Константы подробно (англ.)
- Constants — https://go.dev/blog/constants Статья из блога Go о «константах без типа». Объясняет, почему
int(3.99)не компилируется,int(4.0)компилируется, аx / 2.0при целомxостаётся целочисленным делением.
Почему 0.1 + 0.2 не 0.3 (англ.)
- 0.30000000000000004.com — https://0.30000000000000004.com/ Одна и та же сумма на десятках языков. Результат везде одинаковый: дело не в Go, а в том, как устроены дробные числа в процессоре.
Все глаголы Printf (англ.)
- Пакет fmt — https://pkg.go.dev/fmt В начале описания — таблица глаголов:
%x,%e,%q, ширина и выравнивание. Раздел Format errors — те самые%!d(MISSING). - Команда go vet — https://pkg.go.dev/cmd/vet Какие ещё проверки делает
vet, кроме шаблоновPrintf.
Мини-опыты в ~/gocourse/day03/scratch
- Скидка 7 процентов: возьмите три записи скидки с пятой страницы, поменяйте
pct := 15наpct := 7, посчитайте все три числа на бумаге и сверьте с запуском.
scratch/main.go total := 5997
pct := 7
fmt.Println(total*pct/100, total/100*pct, pct/100*total)- Ширина и выравнивание:
%8d,%-8d|,%8.2f. Напечатайте столбик цен так, чтобы точки стояли друг под другом. - Маленькие целые типы: объявите
var b int8 = 127, прибавьте единицу и напечатайте. Сравните с переполнениемintс шестой страницы. - Большие цены: какая наибольшая сумма в копейках помещается в
int? Сколько это рублей? Хватит ли, если умножить её ещё на 100? - Проценты через дробные числа: для 29 заказов из 50 сравните
29 * 100 / 50иint(float64(29) / float64(50) * 100). Объясните разницу страницей про деньги.