Введение
Зачем в языках программирования нужны переменные? Это давний вопрос. Подобно тому как мы можем запомнить, что URL LabEx — labex.io, компьютерным программам тоже нужно сохранять данные для дальнейшего использования.
Переменные нужны для представления фрагментов данных. В этом разделе мы рассмотрим использование переменных в языке Go.
Основные понятия:
- Объявление переменных
- Инициализация переменных
- Использование переменных
- Время жизни переменных
- Константы
Что такое переменная?
На этом этапе вы узнаете, что представляют собой переменные и какие ограничения Go накладывает на их имена и типы.
Что такое переменная? Если объяснять просто, переменная — это контейнер для хранения изменяемых данных.
В компилируемых языках, таких как Go, тип переменной фиксирован.
Что значит, что тип переменной фиксирован?
Это значит, что переменная может хранить данные только одного типа. Иными словами, содержимое контейнера переменной имеет фиксированный тип.
Если переменная используется для хранения фруктов, она должна содержать только фрукты. После того как в контейнер положили фрукты, использовать его для хранения печенья нельзя. В коде это означает, что переменной нельзя присвоить данные двух разных типов.
Изменяемость переменных
Как следует из названия, значение переменной может изменяться, если новое значение не выходит за пределы, допустимые её типом.
Для переменных в языке Go действуют следующие правила:
- Имя должно состоять из букв, цифр и символов подчёркивания.
- Идентификатор переменной не может начинаться с цифры.
- Идентификатор не может быть зарезервированным ключевым словом. Список зарезервированных ключевых слов
- Имена переменных чувствительны к регистру, однако не рекомендуется различать две переменные с одинаковым именем только регистром букв.
Обычный способ объявления
На этом этапе вы узнаете, как объявлять типизированную переменную с помощью ключевого слова var.
В языке Go для обычного объявления переменных используется ключевое слово var.
Синтаксис объявления: var identifier type, то есть:
var variableName variableType.
Какие типы переменных чаще всего используются в Go?
| Ключевое слово | Объяснение |
|---|---|
int |
Целое число. Наиболее распространённый тип данных, который изучают на уроках математики в начальной школе. |
string |
Строка. Последовательность символов, заключённая в двойные кавычки, например: "hello,world" |
bool |
Логический тип. Представляет значения true или false; возможны два значения: true и false |
Типы переменных не являются основной темой этого раздела, поэтому здесь перечислены только три наиболее распространённых типа.
Другие типы будут рассмотрены в следующих курсах.
Как объявить переменную?
Объявим переменную целого типа с именем a.
var a int
Чтобы запомнить этот синтаксис, мысленно сформулируйте его так:
Define a variable named `a`, which is of type int.
В отличие от многих традиционных языков программирования, в Go тип переменной указывается после её имени.
Такой синтаксис упрощает чтение кода слева направо и не требует «спиральной» логики чтения, характерной для языка C. Подробнее см. в официальной документации.
Как выбрать имя переменной?
Хорошее имя переменной должно ясно показывать, что она означает.
При выборе имён обращайте внимание на их понятность и избегайте сокращений.
Кратко рассмотрим основной способ именования переменных — верблюжью нотацию.
В верблюжьей нотации используются буквы разного регистра. Первое слово начинается со строчной буквы, а первое слово после него — с прописной.
Например: currentDate. Первое слово, current, начинается со строчной буквы, а второе слово, Date, — с прописной.
Благодаря этому сразу понятно, что переменная хранит текущую дату.
Обычно такую нотацию используют для важных и часто применяемых переменных. Имена временных переменных можно сокращать, если это не приводит к совпадениям.
Групповое объявление
На этом этапе вы узнаете, как объявлять несколько переменных одновременно.
Объявим три переменные:
var a int // Declare an integer variable named a
var b int // Declare an integer variable named b
var c int // Declare an integer variable named c
Внимательные учащиеся могли заметить, что все три переменные — a, b, c — имеют тип int.
В таком случае можно соединить имена переменных запятыми и сократить код.
var a, b, c int // Declare three variables a, b, c as integers
Но что делать, если у трёх переменных разные типы?
var a int // Declare an integer variable named a
var b string // Declare a string variable named b
var c bool // Declare a boolean variable named c
Похожую ситуацию можно встретить при импорте пакетов. Если нужно импортировать несколько пакетов с разными именами, их можно записать аналогичным способом:
var (
a int
b string
c bool
)
Обратите внимание: такое групповое объявление, похожее на групповой импорт пакетов, обычно используется для определения глобальных переменных.
Инициализация по умолчанию
На этом этапе вы проверите значения, которые Go назначает переменным по умолчанию.
В Go всем переменным при объявлении присваиваются начальные значения. Давайте выясним, какими они являются.
Создайте файл varExercise.go в каталоге ~/project.
touch ~/project/varExercise.go
Запишите в файл следующий код:
package main
import "fmt"
func main() {
var a int
var b string
var c bool
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
}
Попробуйте запустить программу самостоятельно и проверьте, совпадает ли результат с таблицей ниже.
go run varExercise.go
Начальные значения обобщены в таблице:
| Ключевое слово | Объяснение | Начальное значение |
|---|---|---|
int |
Целое число | 0 |
string |
Строка | "" |
bool |
Логический тип | false |
Явная инициализация
На этом этапе вы явно инициализируете переменные, а затем присвоите им новые значения.
Поскольку тип переменной можно определить по её начальному значению, можно ли изменить значение по умолчанию или значение уже объявленной переменной?
var a int = 1
var b string = "labex"
var c bool = true
a = 233
b = "labex"
c = false
Как показано выше, после объявления переменной нужно поставить =, а затем указать начальное значение, совместимое с типом переменной. Чтобы изменить значение, укажите имя переменной, затем = и новое значение того же типа.
Измените файл varExercise.go:
package main
import "fmt"
func main() {
// Declare and initialize
var a int = 1
var b string = "labex"
var c bool = true
// Print the variables
fmt.Println("Before modification:")
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
// Modify the variables
a = 233
b = "labex"
c = false
// Print the modified variables
fmt.Println("After modification:")
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
}
После запуска программы вывод будет таким:
$ go run varExercise.go
Before modification:
1
labex
true
After modification:
233
labex
false
Попробуйте запустить программу самостоятельно и изменить начальные значения.
Мы уже упоминали, что начальное значение переменной должно иметь тот же тип, что и переменная. Что произойдёт, если типы будут разными?
Например, присвоим переменной a начальное значение "labex":
package main
import "fmt"
func main() {
var a int = "labex"
fmt.Println(a)
}
Запустите программу:
$ go run varExercise.go
## command-line-arguments
./varExercise.go:6:12: cannot use "labex" (type untyped string) as type int in assignment
Как показывает сообщение, строку "labex" нельзя присвоить переменной типа int. Go — строго типизированный компилируемый язык, поэтому такая программа не компилируется.
Вывод типа при объявлении
На этом этапе вы объявите локальные переменные с помощью вывода типа и оператора :=.
Поскольку Go может определить тип переменной по её начальному значению, можно ли упростить объявление и не указывать тип явно?
package main
import "fmt"
func main() {
// var a int = 1
var a = 1 // Type is inferred
fmt.Println(a)
}
Теперь для объявления переменной не обязательно использовать даже ключевое слово var.
Такой способ объявления и инициализации переменных можно сочетать с групповым объявлением:
a, b, c := 0, 0, 0
// Declare variables a, b, c as integers and assign 0 to each variable.
Можно также инициализировать переменные значениями разных типов:
a, b, c := 0, "", true
// Declare variables a, b, c as integer, string, and boolean, respectively.
Для каждой переменной слева от := должно быть соответствующее начальное значение справа.
Краткое объявление очень удобно, но помните: := не является операцией присваивания. Это специальный для Go способ объявления и инициализации локальных переменных внутри функции. Тип переменной автоматически выводится на основе выражения.
Иногда пишут такой код:
func main() {
a := 1
println(a)
a := 2
println(a)
}
Компилятор сообщит об ошибке: переменная a объявлена повторно. Однако следующий вариант корректен:
func main() {
a := 1
if true {
a := 2
println(a) // Output: 2
}
println(a) // Output: 1
}
Такой результат возникает потому, что a со значением 1 и a со значением 2 находятся в разных областях видимости переменных — внутри разных пар фигурных скобок. Поэтому компилятор считает их двумя разными переменными.
Компилятор не укажет на эту ошибку, но программа выведет неожиданный результат.
В Go действует следующее правило:
Каждое выражение вне функции должно начинаться с ключевого слова (var, func и т. д.).
Поэтому краткое объявление переменной можно использовать только для объявления локальных переменных. Для объявления глобальных переменных оно не подходит.
Что же такое глобальная и локальная переменная?
Это связано с понятием времени жизни переменной, которое будет рассмотрено в следующем разделе.
Область видимости переменных
На этом этапе вы сравните области видимости локальных переменных, глобальных переменных и формальных параметров.
Область видимости переменной — это диапазон программы, в котором переменная доступна и может использоваться.
Вы наверняка заметили: если объявить переменную, но не использовать её, код не скомпилируется.
Иными словами, при компиляции Go проверяет, используется ли каждая переменная в пределах своей области видимости.
По месту объявления переменные можно условно разделить на три типа:
- Переменные, объявленные внутри функции, — локальные переменные
- Переменные, объявленные вне функции, — глобальные переменные
- Переменные, объявленные в определении функции, — формальные параметры
Локальные переменные
Большинство переменных, которые мы объявляли в этом разделе, являются локальными:
package main
import "fmt"
func main() { // Function body
var a int = 1 // Local variable
fmt.Println(a)
}
Локальные переменные объявляются внутри тела функции, например a внутри функции main. Область видимости переменной a ограничена функцией main.
Если переменная не используется в функции main, компилятор выдаст ошибку.
Глобальные переменные
Однако переменную можно объявить и как глобальную.
package main
import "fmt"
var a int = 1 // Global variable
func main() { // Function body
fmt.Println(a)
}
Глобальные переменные объявляются вне тела функции, а их область видимости охватывает всю программу. Даже если такая переменная не вызывается ни в одной функции, компилятор не сообщит об ошибке.
Подумайте, почему неиспользуемые глобальные переменные не вызывают ошибок.
Answer
Это связано с тем, что глобальная переменная может использоваться в другом пакете.
Подробно формальные параметры будут рассмотрены в последующих курсах, посвящённых функциям.
Время жизни переменных
На этом этапе вы узнаете, как долго переменные остаются доступными и почему переменную нельзя повторно объявить в одной и той же области видимости.
Улетевшие птицы скрывают простор. Замыслившие зайцы гибнут, а гончие будут вариться. — «Исторические записки»
Когда переменная завершает выполнение своей задачи, её следует уничтожить, чтобы уменьшить расход памяти.
- Глобальные переменные: время жизни глобальной переменной совпадает со всем временем работы программы. Когда программа завершает работу, глобальная переменная удаляется из памяти.
- Локальные переменные: когда получить доступ к переменной больше невозможно, занимаемая ею область памяти освобождается.
Такое устройство — одна из причин высокой производительности Go и эффективного использования памяти.
В течение времени жизни переменную нельзя объявить повторно.
Добавьте в varExercise.go следующий код:
package main
import "fmt"
func main() {
var a int = 1 // Local variable, lifetime is limited to the entire main function
var a int = 2 // Redefinition
fmt.Println(a)
}
Запустите программу:
go run varExercise.go
Вы увидите следующее сообщение об ошибке:
./varExercise.go:7:9: a redeclared in this block
previous declaration at ./varExercise.go:6:9
Компилятор сообщает, что переменная a объявлена повторно.
Константы
На этом этапе вы объявите константы и определите, какие выражения могут быть допустимыми значениями констант.
Многие вещи в жизни похожи на константы. Мы можем их воспринимать, но не можем изменить.
Если значение переменной не будет меняться на протяжении всей работы программы, её следует объявить как константу.
Константы очень похожи на переменные. Их можно представить как переменные с неизменяемыми значениями.
При объявлении константы достаточно заменить ключевое слово var на const.
const Pi = 3.14159 // Using type inference initialization
Создайте файл constExercise.go в каталоге ~/project.
touch ~/project/constExercise.go
Что произойдёт, если попытаться изменить константу?
package main
import "fmt"
func main() {
const Pi = 3.14159
Pi = 2 // Error: cannot assign to Pi
fmt.Println(Pi)
}
Запустите программу.
$ go run constExercise.go
## command-line-arguments
./constExercise.go:7:8: cannot assign to Pi
Компилятор сообщает, что значение Pi нельзя присвоить повторно.
При объявлении константы необходимо указать начальное значение.
Кроме того, начальное значение константы должно быть фиксированным уже во время компиляции.
Возвращаемые значения пользовательских функций в Go не считаются фиксированными.
var a int = 1
// Value is fixed, declaration is valid.
const Pi = 3.14159
// The calculated value is also fixed, the declaration is valid.
const c = 1 / Pi
// Fixed return value from built-in function is valid.
const le = len("labex")
// The return value of the user-defined function is not fixed, the declaration is invalid.
const le = getLen("labby")
// `a` is a variable value that is not fixed, the declaration is invalid.
const k = a
Допустимость объявления константы можно обобщить в таблице:
| Тип объявления | Допустимо |
|---|---|
| Фиксированные значения и выражения с фиксированными значениями | Допустимо |
| Нефиксированные значения (переменные) и соответствующие выражения | Недопустимо |
Встроенная функция (len()) получает фиксированное значение и выражения с фиксированными значениями |
Допустимо |
| Пользовательские функции | Недопустимо |
Итоги
Повторим, что вы изучили в этой лабораторной работе:
- Способы объявления переменных
- Способы инициализации переменных
- Понятие времени жизни переменной
- Использование констант и проверку допустимости их объявлений
В этой лабораторной работе мы рассмотрели основные способы использования переменных в Go, показали, как объявлять и использовать переменные в разных ситуациях, а также познакомились с константами.



