Распространенные грамматические ошибки в Go
1. Открывающие фигурные скобки нельзя размещать на отдельной строке.
код ошибки:
package main
import "fmt"
func main()
{
fmt.Println("hello world!")
}
Ошибка компиляции:
./main.go:5:6: missing function body for "main"
./main.go:6:1: syntax error: unexpected semicolon or newline before {
Правильный код:
package main
import "fmt"
func main() {
fmt.Println("hello world!")
}
2. Неиспользуемые переменные
Если у вас есть неиспользуемые локальные переменные, код не скомпилируется.
Если вы присвоите новое значение неиспользуемой переменной, код все равно не скомпилируется. Вам нужно где-то использовать эту переменную, чтобы компилятор успешно компилировался.
код ошибки:
package main
var gvar int
func main() {
var one int
two := 2
var three int
three = 3
}
Ошибка компиляции:
./main.go:6:6: one declared and not used
./main.go:7:9: two declared and not used
./main.go:8:6: three declared and not used
Правильный код:
package main
import "fmt"
func main() {
var one int
_ = one
two := 2
fmt.Println(two)
var three int
three = 3
one = three
var four int
four = four
}
// Вы также можете закомментировать или удалить неиспользуемые переменные
3. Неиспользованный импорт
Если вы импортируете пакет без использования каких-либо его функций, интерфейсов, структур или переменных, код не скомпилируется.
Если вам действительно нужно импортировать пакет, вы можете добавить знак подчеркивания «_» в качестве имени пакета, чтобы избежать сбоя компиляции. Маркер подчеркивания используется для введения, но не используется.
код ошибки:
package main
import (
"fmt"
"log"
"time"
)
func main() {
}
```go
Ошибка компиляции:
./main.go:4:2: imported and not used: “fmt”
./main.go:5:2: imported and not used: “log”
./main.go:6:2: imported and not used: “time”
Правильный код:
```go
package main
import (
_ "fmt"
"log"
"time"
)
var _ = log.Println
func main() {
_ = time.Now
}
// Вы также можете удалить или закомментировать неиспользуемый импорт
4. «: =» Простое объявление переменной можно использовать только внутри функции.
код ошибки:
package main
myvar := 1
func main() {
}
Ошибка компиляции:
./main.go:3:1: syntax error: non-declaration statement outside function body
Правильный код:
package main
var myvar = 1
func main() {
}
5. Используйте краткие объявления для многократного объявления переменных.
Вы не можете повторно объявлять переменную в одном объявлении, но это разрешено в объявлении с несколькими переменными, где должна быть включена по крайней мере одна новая объявленная переменная.
Повторяющиеся переменные должны находиться в одном блоке кода, иначе вы получите скрытую переменную.
код ошибки:
package main
func main() {
one := 0
one := 1
}
Ошибка компиляции:
./main.go:5:6: no new variables on left side of :=
Правильный код:
package main
func main() {
one := 0
one, two := 1, 2
one, two = two, one
}
6. В названии языка Go учитывается регистр.
код ошибки:
package main
import "fmt"
func main() {
fmt.println("Hello world")
}
// Все следующие коды неверны:
// Package main
// iMport "fmt"
// import "Fmt"
// Func main() {}
// Fmt.Println
// fmt.println
Ошибка компиляции:
./main.go:6:2: cannot refer to unexported name fmt.println
./main.go:6:2: undefined: fmt.println
Правильный код:
package main
import "fmt"
func main() {
fmt.Println("Hello world")
}
7. Точка с запятой в языке Go.
код ошибки:
package main
import "fmt"
func main() {
fmt.Println("Hello world") fmt.Println("Hi again")
}
Ошибка компиляции:
./main.go:6:29: syntax error: unexpected fmt at end of statement
Правильный код:
package main
import "fmt"
func main() {
fmt.Println("Hello world")
// Чтобы решить вышеуказанные проблемы, вы можете поместить два вышеуказанных оператора в две строки
fmt.Println("Hi again")
// Вы можете заканчивать два оператора точкой с запятой
fmt.Println("Hello world");fmt.Println("Hi again")
test()
}
func test() {
// Таким образом, в языке Go точка с запятой может быть сохранена. Если вам необходимо ее использовать, вы можете добавить ее без ошибок.
fmt.Println("Hello world");fmt.Println("Hi again");
};
8. Недопустимая точка с запятой в языке Go.
код ошибки:
package main
import "fmt";;
func main() {
fmt.Println("Hello world")
}
Ошибка компиляции:
./main.go:3:14: syntax error: non-declaration statement outside function body
Правильный код:
package main
import "fmt";
func main() {
fmt.Println("Hello world")
}
9. Обратите внимание на область видимости переменных в языке Go.
код ошибки:
package main
var num int
func main() {
str := "hello world"
if true {
var b bool
}
println(num)
println(str)
println(b)
}
Ошибка компиляции:
./main.go:12:10: undefined: b
Правильный код:
package main
var num int
func main() {
str := "hello world"
if true {
var b bool
println(b)
}
println(num)
println(str)
}
10. Случайное скрытие переменной
Синтаксис краткого объявления переменных настолько удобен (особенно для разработчиков, которые использовали динамические языки), что люди легко могут рассматривать его как обычную операцию присваивания. Если вы сделаете эту ошибку в новом блоке кода, ошибок компиляции не будет, но ваше приложение не будет делать то, что вы ожидаете.
package main
import "fmt"
func main() {
x := 1
fmt.Println(x) // 1
{
fmt.Println(x) // 1
x := 2
fmt.Println(x) // 2
}
fmt.Println(x) // 1
}
результат операции:
1
1
2
1
Даже для опытных разработчиков Go это обычная ловушка, но ее трудно обнаружить.
Вы можете использовать команду vet, чтобы найти некоторые из этих проблем. По умолчанию ветеринар не будет выполнять такие проверки, вам нужно установить параметр -shadow:
Команда: go tool vet -shadow your_file.go
go tool vet -shadow main.go
main.go:10: declaration of "x" shadows declaration at main.go:6
11. Без использования явных типов нельзя использовать «nil» для инициализации переменных.
Флаг nil используется для представления «нулевого значения» интерфейсов, функций, карт, срезов и каналов. Если вы не укажете тип переменной, компилятор не сможет скомпилировать ваш код, потому что он не может угадать конкретный тип.
код ошибки:
package main
func main() {
var x = nil
_ = x
}
Ошибка компиляции:
./main.go:4:6: use of untyped nil
Правильный код:
package main
func main() {
var x interface{} = nil
_ = x
}
12. Используйте нулевые фрагменты и карты.
Добавление элементов в нулевой фрагмент — это нормально, но выполнение того же действия для карты вызовет панику во время выполнения.
Правильный код:
package main
func main() {
var s []int
s = append(s, 1)
}
код ошибки:
package main
import (
"fmt"
)
func main() {
var m map[int]int
m[1] = 1
fmt.Println(m)
}
Ошибка выполнения:
panic: assignment to entry in nil map
Правильный код:
package main
import (
"fmt"
)
func main() {
var m map[int]int
m = make(map[int]int)
m[1] = 1
fmt.Println(m)
}
13. Вместимость карты
карта имеет только операцию len, без операции ограничения
код ошибки:
package main
import (
"fmt"
)
func main() {
m := map[int]string{1: "a", 2: "b", 3: "c"}
cap := cap(m)
fmt.Println(cap)
}
Ошибка компиляции:
./main.go:9:12: invalid argument m (type map[int]string) for cap
Правильный код:
package main
import (
"fmt"
)
func main() {
m := map[int]string{1: "a", 2: "b", 3: "c"}
len := len(m)
fmt.Println(len)
}
14. Строка не будет нулевой.
Это место, на которое следует обратить внимание разработчиков, которые часто используют nil для выделения строковых переменных.
package main
func main() {
var x string = nil
if x == nil {
x = "default"
}
}
Ошибка компиляции:
./main.go:4:6: cannot use nil as type string in assignment
./main.go:5:7: invalid operation: x == nil (mismatched types string and nil)
Правильный код:
package main
func main() {
var x string
if x == "" {
x = "default"
}
}
Variables are containers for storing data values.
Go Variable Types
In Go, there are different types of variables, for example:
int
— stores integers (whole numbers), such as 123 or -123float32
— stores floating point numbers, with decimals, such as 19.99 or -19.99string
— stores text, such as «Hello World». String values are surrounded by double quotesbool
— stores values with two states: true or false
More about different variable types, will be explained in the Go Data Types chapter.
Declaring (Creating) Variables
In Go, there are two ways to declare a variable:
1. With the var
keyword:
Use the var
keyword, followed by variable name and type:
Syntax
var variablename type = value
Note: You always have to specify either type
or value
(or both).
2. With the :=
sign:
Use the :=
sign, followed by the variable value:
Syntax
variablename := value
Note: In this case, the type of the variable is inferred from the value
(means that the compiler decides the type of the variable, based on the value).
Note: It is not possible to declare a variable using
:=
, without assigning a value to it.
Variable Declaration With Initial Value
If the value of a variable is known from the start, you can declare the variable and assign a value to it
on one line:
Example
package main
import («fmt»)
func main() {
var student1 string = «John» //type is
string
var student2 = «Jane» //type is inferred
x := 2 //type is inferred
fmt.Println(student1)
fmt.Println(student2)
fmt.Println(x)
}
Try it Yourself »
Note: The variable types of student2
and x
is inferred from
their values.
Variable Declaration Without Initial Value
In Go, all variables are initialized. So, if you declare a variable without an initial value,
its value will be set to the default value of its type:
Example
package main
import («fmt»)
func main() {
var a string
var b int
var c bool
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
}
Try it Yourself »
Example explained
In this example there are 3 variables:
a
b
c
These variables are declared but they have not been assigned initial values.
By running the code, we can see that they already have the default values of their respective types:
a
is""
b
is0
c
isfalse
Value Assignment After Declaration
It is possible to assign a value to a variable after it is declared. This is helpful for cases the value is not initially known.
Example
package main
import («fmt»)
func main() {
var student1 string
student1 = «John»
fmt.Println(student1)
}
Try it Yourself »
Note: It is not possible to declare a variable using «:=
» without assigning a value to it.
Difference Between var and :=
There are some small differences between the var
var :=
:
var | := |
---|---|
Can be used inside and outside of functions | Can only be used inside functions |
Variable declaration and value assignment can be done separately | Variable declaration and value assignment cannot be done separately (must be done in the same line) |
Example
This example shows declaring variables outside of a function, with the var
keyword:
package main
import («fmt»)
var a int
var b int = 2
var c = 3
func main() {
a = 1
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
}
Try it Yourself »
Example
Since :=
is used outside of a function, running the program results in an error.
package main
import («fmt»)
a := 1
func main() {
fmt.Println(a)
}
Result:
./prog.go:5:1: syntax error: non-declaration statement outside function body
Try it Yourself »
Go Exercises
Синтаксическая ошибка Golang Go: оператор без объявления вне тела функции
Функция makeEvenGenerator
должен возвращать функцию, которая последовательно генерирует четные числа:
package main import 'fmt' func makeEvenGenerator() func() uint { i := uint(0) return func() (ret uint) { ret = i i += 2 return } }func main() { nextEven := makeEvenGenerator() fmt.Println(nextEven()) // 0 fmt.Println(nextEven()) // 2 fmt.Println(nextEven()) // 4 }
При запуске выдает ошибку syntax error: unexpected func, expecting semicolon or newline
а также Non-declaration statement outside function body
.
Код дословно взят из Введение в программирование на Go пользователя Caleb Doxsey. Я не уверен, в чем проблема.
Вам не хватает новой строки между «}» в конце makeEvenGenerator
и «func» в main
.
Исправил ошибку и выложил код на площадку.
- ООО Спасибо. Я не думал, что компилятор заботится о новой строке там, поскольку две части разделены фигурными скобками.
Существуют правила использования точек с запятой.
Спецификация языка программирования Go
Точка с запятой
В формальной грамматике используются точки с запятой «;» в качестве ограничителей в ряде постановок. Программы Go могут опускать большинство этих точек с запятой, используя следующие два правила:
- Когда ввод разбивается на токены, точка с запятой автоматически вставляется в поток токенов в конце непустой строки, если последний токен строки является идентификатором целочисленного, с плавающей запятой, воображаемого, рунического или строкового литерала одним из ключевые слова break, continue, fallthrough или возвращают один из операторов и разделителей ++, -,),] или}
- Чтобы позволить сложным операторам занимать одну строку, точку с запятой можно опустить перед закрывающими «)» или «}».
Ошибка здесь,
}func main() {
Напишите,
} func main() {
Вам не хватало новой строки между }
в конце makeEvenGenerator
а также func main
.
Также альтернативный подход для этого шаблона — использовать канал, не возвращающий функцию:
func evenGenerator() <-chan uint { ch := make(chan uint) go func() { i := uint(0) for { ch <- i i += 2 } }() return ch } func main() { evens := evenGenerator() for i := 0; i < 3; i++ { fmt.Println(<-evens) } }
детская площадка
- 1 Это альтернативный подход, а не «обычный подход». Например, в этом случае использование канала приводит к стократному снижению производительности: 3481 нс / операцию по сравнению с 34,4 нс / операцию.
- @peterSO Хорошее замечание, обновлено. Кстати, скорость канала резко улучшилась: 1,4, 211 нс против 2,23 нс на кончике.
Tweet
Share
Link
Plus
Send
Send
Pin