У меня есть его код, который я написал, чтобы узнать о Голанге. Теперь я сделал отступ в строке «b := 2». Но компилятор вообще не выдал ошибки, а нормально запустил программу. Раньше я использовал Python, поэтому мне это кажется очень странным. Я не смог найти в Интернете причину того, как golang делает эту работу без ошибок. Не могли бы вы объяснить мне, почему это приемлемо для компилятора golang?
package main
import "fmt"
func main() {
a := 1
b := 2
fmt.Println(a,b)
}
Идея в моей голове:
Никаких точек с запятой в конце строк, поэтому строгое форматирование кода.
Чтобы получить ошибку отступа в строке, где я разместил случайные отступы.
Средство форматирования кода Golang в VS-Code (IDE, которое я использую) удаляет эти отступы, когда я пытаюсь сохранить его с помощью команды Ctrl+S, но когда я специально копирую код в текстовый редактор и сохраняю оттуда, а затем запускаю его. код. Компилятор по-прежнему не выдает никаких ошибок.
Все программы, которые соответствуют спецификации языка go, действительны. Спецификация языка go говорит, какие пробелы важны, а какие нет (например, существуют правила относительно новой строки, но отступы почти полностью не важны). Go — это не Python, и у него другие правила. Спецификацию языка можно найти здесь: go.dev/ref/spec
«У меня в голове есть идея», с которой вы затем экспериментируете для проверки, — это хороший подход к обучению, но обращение к исходному материалу (в данном случае к спецификации), как только вы думаете, что поняли (или находитесь в замешательстве), является хорошей секундой. шаг (прежде чем просить о помощи) и вопросы о языке гораздо лучше, чем поиск в сети. Спецификацию языка go довольно легко читать.
Компилятор Go видит точки с запятой, вставленные токенизатором. Вам просто не обязательно их вводить, в «Спецификации языка программирования Go: точки с запятой» сказано:
Программы Go могут опускать большую часть этих точек с запятой [...]
[...] точка с запятой автоматически вставляется в поток токенов сразу после последнего токена строки, если этот токен
- идентификатор
- целочисленный, с плавающей запятой, мнимый, рунический или строковый литерал
- одно из ключевых слов
break
,continue
,fallthrough
илиreturn
- один из операторов и знаков препинания
++
,--
,)
,]
или}
[...] точка с запятой может быть опущена перед закрывающим ")" или "}"
Таким образом, эти точки с запятой автоматически вставляются токенизатором (который видит конец строки и может вставить точку с запятой). Вы увидите несколько точек с запятой в однострочных строках, но держу пари, что они встречаются редко (Go Playground):
package main
import "fmt"
func main() {
world := func() string { name := "world"; return name }
fmt.Println("Hello,", world())
}
Python использует логические строки:
Конец логической строки обозначается маркером NEWLINE. Операторы не могут пересекать границы логических строк, за исключением случаев, когда NEWLINE разрешен синтаксисом (например, между операторами в составных операторах).
Таким образом, токенизатор работает по-другому и NEWLINE
является частью спецификации языка Python, хотя его нет в Go.
Почему фраза «[Go] использует символы новой строки для разделения операторов» неверна? Следующий код не компилируется (Go Playground):
package main
import "fmt"
func main() {
a :=
1
b
:= 2
fmt.Println(a, b)
}
сообщение ./prog.go:9:3: syntax error: unexpected :=
, поэтому мы получаем ошибку := 2
, а не a :=
Почему это? После того как токенизатор вставил точки с запятой, компилятор видит
func main() {
a :=
1;
b;
:= 2;
fmt.Println(a, b);
}
Итак, утверждение a := 1
верно, := 2
нет. Это не совсем понятно с «использованием новой строки для разделения операторов».
В нормальных обстоятельствах он предназначен для работы так, как ожидается, без необходимости тратить слишком много времени на размышления, но полезно понять, почему определенные конструкции работают (или не работают), например
func main() {
a := 1
b := 2
fmt.
Println(a, b)
}
быть действительным и
func main() {
a := 1
b := 2
fmt
.Println(a, b) // ❌
}
будучи недействительным.
В качестве патологического примера:
func main() {
for
i :=
0
i <
5
i++ {
fmt.
Println(
i,
)
}
}
действителен (Go Playground). В JavaScript это не так, поскольку правила там другие:
for (
let
i
=
0
;
i
<
5
;
i++
)
{
console
.
log
(
i
)
}
Иногда полезно использовать разрывы строк для форматирования кода в нужных местах, и они не обязательно приводят к автоматической вставке точки с запятой, если вы знаете правила.
Я чувствую, что это не отвечает на вопрос ОП. Речь шла не о том, необходимы точки с запятой или нет, а о том, как компилятор golang обрабатывает инструкции иначе, чем это делает Python (или его разновидности).
Компилятор Go видит точки с запятой, которых нет в исходном коде, но они автоматически вставляются токенизатором. Итак, точки с запятой есть, что касается компилятора - вам просто не нужно их вводить. Почему это не отвечает на вопрос?
Привет. Спасибо за ответ, он развеял некоторые мои сомнения. Это было полезно!
Python использует пробелы (по крайней мере) двумя разными способами:
#2 зависит от #1 — отступ зависит от символов новой строки, потому что вся концепция отступов заключается в том, что они идут в начале строки — но #1 не зависит от #2: мы можем представить язык, который использует символы новой строки для разделения операторы, но для обозначения тела блока используются фигурные скобки или другие обозначения.
. . . за исключением того, что нам даже не нужно это представлять, потому что, как вы заметили, Go — такой язык!
Другие подобные языки включают оболочки JavaScript и POSIX (например, Bash).
(Все эти языки также поддерживают точки с запятой для разделения операторов — вместо или вместе с символами новой строки — но одних символов новой строки достаточно.)
Спасибо за объяснение! Это на самом деле объясняет мне, как это можно реализовать в компиляторе и как компилятор go работает под капотом!
Go не использует символы новой строки для разделения операторов, вы ошибаетесь. Видите ли вы здесь какие-нибудь новые строки: go.dev/ref/spec#Blocks ? В Python используются символы новой строки, а в Go — нет, используются точки с запятой.
@eik: Извините, но я просто не согласен с вашей точкой зрения на этот счет. Как указано в вашем ответе, Go автоматически вставляет точки с запятой в новые строки. Это преднамеренный аспект дизайна языка, который намеренно позволяет простому символу новой строки разделять операторы. Аналогичным образом, подавляющее большинство программ Go намеренно не включают точки с запятой, а официальный форматировщик Go удаляет точки с запятой. Конечным результатом является то, что операторы обычно разделяются символами новой строки, а точки с запятой служат главным образом для удобства спецификации. Мне жаль, если это тебя обидело.
Мне ужасно жаль, что Вы обиделись на поправку, и прошу прощения. Посмотрите мой обновленный ответ, чтобы понять, почему «представьте, что Go использует символы новой строки для разделения операторов» неверно. Автоматическая вставка точки с запятой — это то, что JavaScript также использует, и очень полезно понимать правила, которые вы не можете сделать, «разрешая простому символу новой строки разделять операторы», особенно если вы хотите разбить строку для удобства чтения, не начиная новое заявление.
Отступы не имеют значения в golang и большинстве других языков программирования, кроме Python. Python использует отступы для определения блоков, golang использует фигурные скобки.