Введение в переменные в Go

GolangGolangBeginner
Практиковаться сейчас

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

Почему нам нужны переменные в языках компьютерного программирования? Это давний вопрос. Так же, как мы можем запомнить, что URL-адрес LabEx - это labex.io, компьютерные программы также должны запоминать некоторые данные для своего использования.

Цель переменных - представить кусок данных. В этом разделе мы рассмотрим, как используются переменные в языке Go.

Точки знания:

  • Объявление переменных
  • Инициализация переменных
  • Использование переменных
  • Время жизни переменных
  • Константы

Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL go(("Golang")) -.-> go/BasicsGroup(["Basics"]) go(("Golang")) -.-> go/DataTypesandStructuresGroup(["Data Types and Structures"]) go(("Golang")) -.-> go/FunctionsandControlFlowGroup(["Functions and Control Flow"]) go/BasicsGroup -.-> go/values("Values") go/BasicsGroup -.-> go/constants("Constants") go/BasicsGroup -.-> go/variables("Variables") go/DataTypesandStructuresGroup -.-> go/strings("Strings") go/DataTypesandStructuresGroup -.-> go/structs("Structs") go/FunctionsandControlFlowGroup -.-> go/if_else("If Else") go/FunctionsandControlFlowGroup -.-> go/functions("Functions") subgraph Lab Skills go/values -.-> lab-149065{{"Введение в переменные в Go"}} go/constants -.-> lab-149065{{"Введение в переменные в Go"}} go/variables -.-> lab-149065{{"Введение в переменные в Go"}} go/strings -.-> lab-149065{{"Введение в переменные в Go"}} go/structs -.-> lab-149065{{"Введение в переменные в Go"}} go/if_else -.-> lab-149065{{"Введение в переменные в Go"}} go/functions -.-> lab-149065{{"Введение в переменные в Go"}} end

Что такое переменная?

Что такое переменная? Простыми словами, переменная - это контейнер, используемый для хранения и сохранения части изменяемой информации.

В компилируемых языках, таких как Go, тип переменной фиксирован.

Что значит, что тип переменной фиксирован?

Это означает, что переменная может хранить только один тип данных. Другими словами, элементы, хранящиеся в контейнере переменной, фиксированы.

Если переменная используется для хранения фруктов, она должна хранить только фрукты. Как только контейнер был использован для хранения фруктов, его нельзя использовать для хранения печенья. В коде это проявляется в том, что переменной нельзя присвоить два разных типа данных.

Изменяемость переменной

Как следует из названия, значение переменной может изменяться, если это изменение не выходит за пределы допустимого для ее типа диапазона.

В языке Go действуют следующие правила для переменных:

  • Имя должно состоять из букв, цифр и знаков подчеркивания.
  • Идентификатор переменной не может начинаться с цифры.
  • Идентификатор не может быть зарезервированным ключевым словом. Проверить зарезервированные ключевые слова
  • Имена переменных чувствительны к регистру, но не рекомендуется использовать разный регистр для различения двух переменных с одинаковым именем.

Общий метод объявления

В языке Go ключевое слово, используемое для объявления переменных общим методом, - это var.

Форма объявления имеет вид: var идентификатор тип, что означает:

var имя_переменной тип_переменной.

Какие типы переменных часто используются в Go?

Ключевое слово Описание
int Целое число. Самый распространенный тип данных, изучаемый в начальной школе.
string Строка. Последовательность символов, заключенных в двойные кавычки, например: "hello,world"
bool Логический тип. Представляет истину или ложь, может принимать два значения: true или false

Поскольку типы переменных не являются фокусом данного раздела, здесь перечислены только три наиболее распространенных типа.

Более подробно о других типах будет рассказано в следующих уроках.

Как объявить переменную?

Теперь давайте объявим целую переменную с именем a.

var a int

Как запомнить это? Вы можете прошептать себе в уме:

Определить переменную с именем `a`, которая имеет тип int.

В отличие от многих традиционных языков программирования, в Go тип переменной указывается после ее имени.

Такой способ объявления переменных делает код легче читаемым слева направо и избавляет от "спиральной" логики чтения, характерной для языка C. Подробнее см. в официальной документации.

Какое имя дать переменной?

Хорошее имя переменной должно четко указывать ее смысл.

При именовании переменных необходимо обращать внимание на их выразительность и избегать использования сокращений.

Вот мы кратко рассмотрим базовый метод именования переменных: стиль именования "верблюжий регистр" (Camel Case Naming Convention).

Стиль именования "верблюжий регистр" использует смешанный регистр букв для обозначения переменной. Первое слово пишется в нижнем регистре, а первая буква каждого последующего слова - в верхнем регистре.

Например: currentDate. Первое слово, current, написано в нижнем регистре, а второе слово, Date, начинается с заглавной буквы.

Таким образом, переменная, представляющая текущую дату, легко понимается.

Этот стиль именования обычно используется для важных и часто используемых переменных, в то время как временные переменные могут быть упрощены, если это не приводит к дублированию.

Метод пакетного объявления

Теперь давайте объявим три переменные:

var a int // Объявить целочисленную переменную с именем a
var b int // Объявить целочисленную переменную с именем b
var c int // Объявить целочисленную переменную с именем c

Внимательные студенты, возможно, заметили, что все три переменные a, b, c имеют тип int.

В таком случае мы можем использовать запятую для соединения имен переменных и сократить объем кода.

var a, b, c int // Объявить три переменные a, b, c как целочисленные

Но что делать, если три переменные имеют разные типы?

var a int    // Объявить целочисленную переменную с именем a
var b string // Объявить строковую переменную с именем b
var c bool   // Объявить логическую переменную с именем c

Мы, похоже, столкнулись с аналогичной ситуацией при импорте пакетов. Необходимо импортировать вместе много пакетов с разными именами, поэтому мы можем использовать аналогичный способ записи:

var (
    a int
    b string
    c bool
)

Обратите внимание, что такой способ объявления, аналогичный импорту пакетов, обычно используется для определения глобальных переменных.

Стандартная инициализация

В 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() {
    // Объявление и инициализация
    var a int = 1
    var b string = "labex"
    var c bool = true

    // Вывод переменных
    fmt.Println("Before modification:")
    fmt.Println(a)
    fmt.Println(b)
    fmt.Println(c)

    // Изменение переменных
    a = 233
    b = "labex"
    c = false

    // Вывод измененных переменных
    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

Вы можете попробовать запустить код самостоятельно и изменить начальные значения.

Мы только что упомянули, что начальное значение, присваиваемое переменной, должно быть того же типа, что и объявление переменной. Что произойдет, если они будут разными?

Например, давайте присвоим "labex" в качестве начального значения переменной a:

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 // Тип выводится автоматически
    fmt.Println(a)
}

Теперь вы даже не обязаны использовать ключевое слово var для определения переменной.

Такой способ объявления и инициализации переменной также можно сочетать с методом пакетного объявления:

a, b, c := 0
// Объявить переменные a, b, c как целочисленные и присвоить им начальное значение 0
a, b, c := 0, "", true
// Объявить переменные a, b, c соответственно как целочисленную, строковую и логическую

Короткое объявление очень удобно, но будьте осторожны, так как := не является операцией присваивания. Это способ объявления переменных, уникальный для Go, используемый для объявления и инициализации локальных переменных внутри функции. Тип переменной будет автоматически определен на основе выражения.

Иногда мы пишем следующий код:

func main() {
    a := 1
    println(a)
    a := 2
    println(a)
}

Компилятор сообщит вам, что в коде есть ошибка, потому что переменная a была переобъявлена. Однако, если написать код следующим образом:

func main() {
    a := 1
    if true {
        a := 2
        println(a) // Вывод: 2
    }
    println(a) // Вывод: 1
}

Такой вывод получается потому, что переменная a со значением 1 выше и переменная a со значением 2 ниже находятся в разных областях видимости переменных (внутри разных фигурных скобок), поэтому компилятор воспринимает их как две разные переменные.

Компилятор не укажет на вашу ошибку, но может появиться неожиданный вывод.

В Go установлено, что:

Каждая инструкция вне функции должна начинаться с ключевого слова (var, func и т.д.).

Поэтому краткое объявление переменных можно использовать только для объявления локальных переменных и не может быть использовано для объявления глобальных переменных.

Так что такое глобальная переменная, а что такое локальная переменная?

Это связано с концепцией времени жизни переменной, которая будет рассмотрена в следующем разделе.

Область видимости переменных

Область видимости переменной — это диапазон, в котором переменная в программе действует, то есть как она может быть использована.

Вы, наверное, заметили, что если объявить переменную, но не использовать ее, код не скомпилируется.

Другими словами, при компиляции Go проверяет, была ли использована каждая переменная, то есть была ли она использована в своей области видимости.

Мы можем просто разделить переменные на три типа в зависимости от места их объявления:

  • Переменные, определенные внутри функции, называются локальными переменными.
  • Переменные, определенные вне функции, называются глобальными переменными.
  • Переменные, определенные в определении функции, называются формальными параметрами.

Локальные переменные

В этом разделе большинство переменных, которые мы определяем, являются локальными:

package main

import "fmt"

func main() { // Тело функции
    var a int = 1 // Локальная переменная
    fmt.Println(a)
}

Локальные переменные определяются внутри тела функции, например, a, определенная внутри функции main. Область видимости переменной a ограничена функцией main.

В то же время, если переменная не используется в функции main, компилятор выдаст ошибку.

Глобальные переменные

Однако можно также определить глобальную переменную.

package main

import "fmt"

var a int = 1 // Глобальная переменная
func main() { // Тело функции
    fmt.Println(a)
}

Глобальные переменные определяются вне тела функции, и их область видимости охватывает всю программу. Даже если они не вызываются ни в одной функции, компилятор не выдаст ошибки.

Подумайте, почему глобальные переменные не вызывают ошибок, даже если они не вызываются.

Ответ

Это происходит потому, что глобальная переменная может быть вызвана в другом пакете.

Подробности о формальных параметрах будут рассмотрены в последующих курсах, связанных с функциями.

Время жизни переменных

Летающие птицы улетели, и охотники прячут свои лука. Убиты козлиные зайцы, и охотничьи собаки отправляются на суп. — «История великого летописца»

Когда переменная выполнила свою задачу, ее следует уничтожить, чтобы уменьшить использование памяти.

  • Глобальные переменные: Время жизни глобальной переменной совпадает с временем выполнения всей программы. Когда программа прекращает работу, глобальная переменная удаляется из памяти.
  • Локальные переменные: Когда нет возможности получить доступ к переменной, ее память освобождается.

Такая конструкция является ключом к высокой производительности и эффективному использованию памяти в Go.

В течение времени жизни переменной ее нельзя переобъявлять.

Вы можете написать следующий код в файле varExercise.go:

package main

import "fmt"

func main() {
    var a int = 1 // Локальная переменная, время жизни ограничено функцией main
    var a int = 2 // Переопределение
    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 // Инициализация с использованием вывода типа

Что произойдет, если мы попытаемся изменить константу?

package main

import "fmt"

func main() {
    const Pi = 3.14159
    Pi = 2 // Ошибка: нельзя присвоить значение 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
// Значение фиксированное, объявление корректно.
const Pi = 3.14159
// Вычисленное значение также фиксированное, объявление корректно.
const c = 1 / Pi
// Фиксированное возвращаемое значение встроенной функции корректно.
const le = len("labex")
// Возвращаемое значение пользовательской функции не фиксировано, объявление некорректно.
const le = getLen("labby")
// `a` - это переменное значение, не фиксированное, объявление некорректно.
const k = a

Валидность объявления константы можно свести в следующую таблицу:

Тип объявления Валидность
Фиксированные значения и выражения с фиксированными значениями Валидно
Непостоянные значения (переменные) и соответствующие им выражения Невалидно
Встроенные функции (len()), получающие фиксированное значение и выражения с фиксированными значениями Валидно
Пользовательские функции Невалидно

Итоги

Проверим, что мы узнали в этом практическом занятии:

  • Способы объявления переменных
  • Способы инициализации переменных
  • Концепция времени жизни переменных
  • Использование констант и валидность их объявлений

В этом практическом занятии мы повторили базовое использование переменных в Go, показали способы объявления и использования переменных в различных ситуациях и познакомились с константами.