Короткое объявление :=
var stock int = 40 — четыре слова ради одной ячейки. Внутри функций переменные обычно объявляют короче. На этой странице — короткая запись и разница между := и =.
:= — объявить и сразу присвоить
Ситуация. Внутри функции нужна переменная с начальным значением — самый частый случай.
package main
import "fmt"
func main() {
stock := 40
item := "Болт М6"
fmt.Println(item, stock)
}Что увидите.
stagiaire@lab:~/gocourse/day02/scratch$ go run .
Болт М6 40Как это читать. stock := 40 делает то же, что var stock int = 40. Знак := читается «объявить и присвоить». Тип не написан — компилятор выводит его из значения: 40 — int, "Болт М6" — string. Выведенный тип закреплён навсегда: число в item не положить. Так же выводит тип и var, если тип не писать: var price = 1200.
| Запись | Когда пишут |
|---|---|
stock := 40 |
внутри функции, когда начальное значение известно, — чаще всего |
var sold int |
когда начинать нужно с нулевого значения |
var price = 1200 |
вне функций, где := нельзя |
Попробуйте сейчас: объявления через
:=.Цель: убедиться, что
:=даёт тот же вывод, а выведенный тип закреплён за переменной.
- В
scratch/main.goс прошлой страницы перепишите через:=оба объявления со значением — товар и остаток; объявление продаж без значения оставьте наvar. Запустите — вывод не должен измениться:▶ Выполнитеcd ~/gocourse/day02/scratch go run .
- Потом проверьте, что выведенный тип закреплён. Замените содержимое
scratch/main.goпрограммой ниже:✎ Наберите в файлscratch/main.gopackage main import "fmt" func main() { stock := 40 item := 7 item = "Гайка" fmt.Println("Остаток:", stock) }и запустите:
▶ Выполнитеgo run .
- Допишите
itemвPrintlnчерез запятую послеstockи запустите снова.Готово, когда: первый запуск программы с
itemдал два сообщения компилятора, второй — одно; разбор — в следующем разделе.
Опыт с item: два сообщения
Что увидите после первого запуска:
stagiaire@lab:~/gocourse/day02/scratch$ go run .
# day02/scratch
./main.go:7:2: declared and not used: item
./main.go:8:9: cannot use "Гайка" (untyped string constant) as int value in assignmentКак это читать. Сообщение про тип — второе. Тип item выведен из 7, это int, и строку "Гайка" в эту ячейку не положить.
Первое сообщение — следствие. Строка item = "Гайка" только записывает в ячейку. Использованной переменная считается, когда её значение читают: печатают или ставят в правую часть присваивания. Здесь item ни разу не прочитали, поэтому declared and not used, хотя имя встречается в двух строках.
После второго запуска, с item в Println, сообщение одно:
stagiaire@lab:~/gocourse/day02/scratch$ go run .
# day02/scratch
./main.go:8:9: cannot use "Гайка" (untyped string constant) as int value in assignmentЕсли в выражении или печати заменить переменную на что-то другое, она может перестать читаться — и к основной ошибке добавится declared and not used.
:= только внутри функции
package main
import "fmt"
stock := 40
func main() {
fmt.Println("Остаток:", stock)
}stagiaire@lab:~/gocourse/day02/scratch$ go run .
# day02/scratch
./main.go:5:1: syntax error: non-declaration statement outside function bodyКак это читать. «Не объявление вне тела функции». Вне функций Go принимает только объявления с ключевым словом: package, import, func, var, const. := работает только внутри функции. С var stock = 40 на строке 5 программа соберётся и напечатает Остаток: 40. Но в первых днях курса всё пишем внутри main.
:= и = — разные действия
| Знак | Что делает | Переменной ещё нет | Переменная уже есть |
|---|---|---|---|
:= |
создаёт новую ячейку и кладёт значение | создаёт | ошибка |
= |
кладёт значение в существующую ячейку | ошибка | заменяет значение |
package main
import "fmt"
func main() {
stock := 40
fmt.Println("Утром:", stock)
stock := 55
fmt.Println("Днём:", stock)
}stagiaire@lab:~/gocourse/day02/scratch$ go run .
# day02/scratch
./main.go:8:8: no new variables on left side of :=«Нет новых переменных слева от :=»: знак обещает создать переменную, а stock уже создана в строке 6. Нужно stock = 55.
Обратная ошибка — stock = 40 без объявления — даёт undefined: stock: положить значение некуда, ячейки нет. Такое сообщение будет на строке stock = 40 и ещё по одному на каждой строке ниже, где упомянута stock.
Сначала объявить, потом использовать
Компилятор читает программу сверху вниз: имя можно использовать только ниже строки, где его объявили.
package main
import "fmt"
func main() {
fmt.Println("Остаток:", stock)
stock := 40
}stagiaire@lab:~/gocourse/day02/scratch$ go run .
# day02/scratch
./main.go:6:33: undefined: stock
./main.go:7:2: declared and not used: stockВ строке 6 ячейки ещё нет, в строке 7 она появляется, но ниже её никто не читает. Два сообщения — одна причина: строки стоят не в том порядке.
Что может пойти не так
| Что видите | Что это значит | Что делать |
|---|---|---|
syntax error: non-declaration statement outside function body |
:= написано вне функции |
перенести строку в main или писать var |
no new variables on left side of := |
:= для переменной, которая уже объявлена |
заменить := на = |
undefined: stock в строке stock = 40, ниже — ещё undefined: stock на каждой строке со stock |
= для переменной, которой ещё нет |
первое появление — через := или var |
undefined: stock, ниже declared and not used: stock |
переменную используют выше объявления | перенести объявление выше |
cannot use "сорок" (untyped string constant) as int value in assignment |
stock := 40, потом stock = "сорок" |
класть значение того же типа |
declared and not used: item, хотя ниже есть item = … |
в переменную только записывали, её значение нигде не читается | прочитать значение — напечатать или поставить в правую часть — либо удалить переменную |
Попробуйте сейчас: почините
fix2и посмотрите правку.Цель:
fix2собирается, аdiffс оригиналом показывает вашу правку — одну строку.Программа
fix2не собирается.
- Запустите и прочитайте сообщение:
▶ Выполнитеcd ~/gocourse/day02/fix2 go run .
- Исправьте одну строку, сохраните и запустите
go run .снова.- Посмотрите свою правку — сравните файл с оригиналом, который курс сохранил при создании стенда:
▶ Выполнитеdiff ~/.course/orig/day02/fix2/main.go main.go
diffпечатает только различающиеся строки. Для примера выше, где в строке 8:=заменили бы на=, вывод такой:Вывод · это печатает программа, набирать не нужно8c8 < stock := 55 --- > stock = 55
8c8— «строка 8 изменилась»; с<— как было, с>— как стало. Проверка считает строки так же и засчитывает починку, если их одна или две: починить, а не переписать.
- Сообщение
no new variables on left side of :=— в~/errors.md.Готово, когда:
go run .печатает две строки из комментария в начале файла — пункт проверкиfix2;diffпоказал вашу правку — пунктt_diff.
Дальше: присваивание — что на самом деле делает = — course next