Variables - важная концепция программирования, которую необходимо освоить. Это символы, которые обозначают значение, которое вы используете в программе.
В этом руководстве рассматриваются некоторые переменные основы и рекомендации по их использованию в создаваемых вами программах Go.
Понимание переменных
В технических терминах переменная назначает место хранения для значения, которое связано с символическим именем или идентификатором. Мы используем имя переменной для ссылки на это сохраненное значение в компьютерной программе.
Мы можем рассматривать переменную как метку с именем, которое вы привязываете к значению.
Допустим, у нас есть целое число1032049348
, и мы хотим сохранить его в переменной, а не постоянно набирать длинное число снова и снова. Для этого мы можем использовать легко запоминающееся имя, например, переменнуюi
. Чтобы сохранить значение в переменной, мы используем следующий синтаксис:
i := 1032049348
Мы можем думать об этой переменной как о метке, привязанной к значению.
На метке написано имя переменнойi
, и она привязана к целочисленному значению1032049348
.
Фразаi := 1032049348
- это объявление и оператор присваивания, состоящий из нескольких частей:
-
имя переменной (
i
) -
присвоение краткого объявления переменной (
:=
) -
значение, которое привязывается к имени переменной (
1032049348
) -
тип данных, определяемый Go (
int
)
Позже мы увидим, как явно установить тип в следующем разделе.
Вместе эти части составляют оператор, который устанавливает переменнуюi
равной значению целого числа1032049348
.
Как только мы устанавливаем переменную равной значению, мыinitialize или создаем эту переменную. Как только мы это сделаем, мы готовы использовать переменную вместо значения.
После того, как мы установилиi
равным значению1032049348
, мы можем использоватьi
вместо целого числа, так что давайте распечатаем его:
package main
import "fmt"
func main() {
i := 1032049348
fmt.Println(i)
}
Output1032049348
Мы также можем быстро и легко сделать математику с помощью переменных. Используяi := 1032049348
, мы можем вычесть целочисленное значение813
с помощью следующего синтаксиса:
fmt.Println(i - 813)
Output1032048535
В этом примере Go выполняет вычисления за нас, вычитая 813 из переменнойi
, чтобы вернуть сумму1032048535
.
Говоря о математике, переменные могут быть установлены равными результату математического уравнения. Вы также можете сложить два числа и сохранить значение суммы в переменнойx
:
x := 76 + 145
Возможно, вы заметили, что этот пример похож на алгебру. Так же, как мы используем буквы и другие символы для представления чисел и величин в формулах и уравнениях, переменные являются символическими именами, представляющими значение типа данных. Для правильного синтаксиса Go вам необходимо убедиться, что ваша переменная находится слева от любых уравнений.
Давайте продолжим и напечатаемx
:
package main
import "fmt"
func main() {
x := 76 + 145
fmt.Println(x)
}
Output221
Go вернул значение221
, потому что переменнаяx
была установлена равной сумме76
и145
.
Переменные могут представлять любой тип данных, а не только целые числа:
s := "Hello, World!"
f := 45.06
b := 5 > 9 // A Boolean value will return either true or false
array := [4]string{"item_1", "item_2", "item_3", "item_4"}
slice := []string{"one", "two", "three"}
m := map[string]string{"letter": "g", "number": "seven", "symbol": "&"}
Если вы напечатаете любую из этих переменных, Go вернет то, чему эквивалентна эта переменная. Давайте поработаем с оператором присваивания для строкового типа данныхslice
:
package main
import "fmt"
func main() {
slice := []string{"one", "two", "three"}
fmt.Println(slice)
}
Output[one two three]
Мы присвоили значение среза[]string{"one", "two", "three"}
переменнойslice
, а затем использовали функциюfmt.Println
, чтобы распечатать это значение, вызвавslice
.
Переменные работают, вырезая небольшую область памяти на вашем компьютере, которая принимает определенные значения, которые затем связываются с этим пространством.
Объявление переменных
В Go есть несколько способов объявить переменную, а в некоторых случаях более одного способа объявить одну и ту же переменную и значение.
Мы можем объявить переменную с именемi
с типом данныхint
без инициализации. Это означает, что мы объявим пробел для установки значения, но не дадим ему начальное значение:
var i int
Это создает переменную, объявленную какi
с типом данныхint
.
Мы можем инициализировать значение с помощью оператора равенства (=
), как в следующем примере:
var i int = 1
В Go обе эти формы объявления называютсяlong variable declarations.
Мы также можем использоватьshort variable declaration:
i := 1
В этом случае у нас есть переменная с именемi
и тип данныхint
. Когда мы не указываем тип данных, Go выводит тип данных.
С помощью трех способов объявления переменных сообщество Go приняло следующие идиомы:
-
Используйте длинную форму,
var i int
, только когда вы не инициализируете переменную. -
При объявлении и инициализации используйте краткую форму
i := 1
. -
Если вы не хотели, чтобы Go выводил ваш тип данных, но вы все еще хотите использовать краткое объявление переменной, вы можете заключить свое значение в желаемый тип со следующим синтаксисом:
i := int64(1)
В Go не считается идиоматичным использование формы объявления длинной переменной, когда мы инициализируем значение:
var i int = 1
Рекомендуется следить за тем, как сообщество Go обычно объявляет переменные, чтобы другие могли беспрепятственно читать ваши программы.
Нулевые значения
Все встроенные типы имеют нулевое значение. Любая выделенная переменная может использоваться, даже если ей никогда не назначается значение. Мы можем видеть нулевые значения для следующих типов:
package main
import "fmt"
func main() {
var a int
var b string
var c float64
var d bool
fmt.Printf("var a %T = %+v\n", a, a)
fmt.Printf("var b %T = %q\n", b, b)
fmt.Printf("var c %T = %+v\n", c, c)
fmt.Printf("var d %T = %+v\n\n", d, d)
}
Outputvar a int = 0
var b string = ""
var c float64 = 0
var d bool = false
Мы использовали глагол%T
в оператореfmt.Printf
. Это указывает функции напечататьdata type
для переменной.
В Go, поскольку все значения имеют значениеzero
, у нас не может быть значенийundefined
, как в некоторых других языках. Например,boolean
на некоторых языках может бытьundefined
,true
илиfalse
, что позволяет использовать состоянияthree
для переменной. В Go для логического значения не может быть больше, чемtwo
состояний.
Переменные именования: правила и стиль
Именование переменных довольно гибкое, но следует помнить о некоторых правилах:
-
Имена переменных должны быть только одним словом (как без пробелов).
-
Имена переменных должны состоять только из букв, цифр и знаков подчеркивания (
_
). -
Имена переменных не могут начинаться с цифры.
Следуя этим правилам, давайте рассмотрим как действительные, так и недействительные имена переменных:
действительный | Недействительным | Почему недействительный |
---|---|---|
|
|
Дефисы не допускаются |
|
|
Не может начинаться с числа |
|
|
Нельзя использовать символы |
|
|
Не может быть больше одного слова |
Кроме того, при именовании переменных имейте в виду, что они чувствительны к регистру. Эти именаuserName
,USERNAME
,UserName
иuSERnAME
- все совершенно разные переменные. Рекомендуется избегать использования одинаковых имен переменных в программе, чтобы гарантировать, что и вы, и ваши сотрудники - нынешние и будущие - могут сохранять ваши переменные прямыми.
Хотя переменные чувствительны к регистру, регистр первой буквы переменной имеет особое значение в Go. Если переменная начинается с заглавной буквы, то эта переменная доступна вне пакета, в котором она была объявлена (илиexported
). Если переменная начинается со строчной буквы, то она доступна только в пакете, в котором она объявлена.
var Email string
var password string
Email
начинается с заглавной буквы и может быть доступен другим пакетам. password
начинается со строчной буквы и доступен только внутри пакета, в котором он объявлен.
В Go часто используются очень краткие (или короткие) имена переменных. Учитывая выбор между использованиемuserName
иuser
для переменной, было бы идиоматично выбратьuser
.
Сфера также играет роль в краткости имени переменной. Правило состоит в том, что чем меньше область действия переменной, тем меньше имя переменной:
names := []string{"Mary", "John", "Bob", "Anna"}
for i, n := range names {
fmt.Printf("index: %d = %q\n", i, n)
}
Мы используем переменнуюnames
в более широкой области, поэтому было бы обычным дать ей более значимое имя, чтобы помочь запомнить, что она означает в программе. Однако мы используем переменныеi
иn
сразу в следующей строке кода, а затем больше не используем их. Из-за этого его не смущает тот, кто читает код о том, где используются переменные или что они значат.
Далее давайте рассмотрим некоторые заметки о переменном стиле. Стиль заключается в использованииMixedCaps
илиmixedCaps
вместо подчеркивания для имен из нескольких слов.
Обычный стиль | Нетрадиционный стиль | Почему нетрадиционный |
---|---|---|
|
|
Подчеркивания не являются общепринятыми |
|
|
предпочитайте |
|
|
акронимы должны быть заглавными |
Самое главное в стиле - это быть последовательным, и команда, над которой вы работаете, соглашается со стилем.
Переназначение переменных
Как следует из слова «переменная», мы можем легко изменять переменные Go. Это означает, что мы можем связать другое значение с ранее назначенной переменной посредством переназначения. Возможность переназначения полезна, потому что на протяжении всей программы нам может потребоваться принять пользовательские значения в уже инициализированные переменные. Нам также может потребоваться изменить назначение на что-то ранее определенное.
Знание того, что мы можем легко переназначить переменную, может быть полезно при работе с большой программой, написанной кем-то другим, и неясно, какие переменные уже определены.
Давайте присвоим значение76
переменной с именемi
типаint
, а затем присвоим ей новое значение42
:
package main
import "fmt"
func main() {
i := 76
fmt.Println(i)
i = 42
fmt.Println(i)
}
Output76
42
Этот пример показывает, что мы можем сначала присвоить переменнойi
значение целого числа, а затем переназначить переменнуюi
, присвоив ей на этот раз значение42
.
[.note] #Note: Когда вы объявляетеand инициализируете переменную, вы можете использовать:=
, однако, если вы хотите просто изменить значение уже объявленной переменной, вам нужно только использовать оператор равенства (=
).
#
Поскольку Go - это языкtyped
, мы не можем присвоить один тип другому. Например, мы не можем присвоить значение"Sammy"
переменной типаint
:
i := 72
i = "Sammy"
Попытка назначить разные типы друг другу приведет к ошибке времени компиляции:
Outputcannot use "Sammy" (type string) as type int in assignment
Go не позволит нам использовать имя переменной более одного раза:
var s string
var s string
Outputs redeclared in this block
Если мы попытаемся использовать краткое объявление переменной более одного раза для одного и того же имени переменной, мы также получим ошибку компиляции. Это может произойти по ошибке, поэтому полезно понять, что означает сообщение об ошибке:
i := 5
i := 10
Outputno new variables on left side of :=
Как и при объявлении переменных, учет имен ваших переменных улучшит читабельность вашей программы для вас и других, когда вы вернетесь к ней в будущем.
Множественное назначение
Go также позволяет нам присваивать несколько значений нескольким переменным в одной строке. Каждое из этих значений может иметь другой тип данных:
j, k, l := "shark", 2.05, 15
fmt.Println(j)
fmt.Println(k)
fmt.Println(l)
Outputshark
2.05
15
В этом примере переменнаяj
была назначена строке"shark"
, переменнаяk
была назначена float2.05
, а переменнаяl
была назначена с целым числом15
.
Такой подход к присвоению нескольких переменных нескольким значениям в одной строке может уменьшить количество строк в вашем коде. Однако важно не ставить под угрозу удобочитаемость для меньшего количества строк кода.
Глобальные и локальные переменные
При использовании переменных в программе важно помнить оvariable scope. Область действия переменной относится к конкретным местам, к которым она доступна из кода данной программы. Это означает, что не все переменные доступны из всех частей данной программы - некоторые переменные будут глобальными, а некоторые локальными.
Глобальные переменные существуют вне функций. Локальные переменные существуют внутри функций.
Давайте посмотрим на глобальные и локальные переменные в действии:
package main
import "fmt"
var g = "global"
func printLocal() {
l := "local"
fmt.Println(l)
}
func main() {
printLocal()
fmt.Println(g)
}
Outputlocal
global
Здесь мы используемvar g = "global"
для создания глобальной переменной вне функции. Затем мы определяем функциюprintLocal()
. Внутри функции назначается и распечатывается локальная переменнаяl
. Программа заканчивается вызовомprintLocal()
и последующей печатью глобальной переменнойg
.
Посколькуg
- глобальная переменная, мы можем ссылаться на нее вprintLocal()
. Давайте изменим предыдущую программу, чтобы сделать это:
package main
import "fmt"
var g = "global"
func printLocal() {
l := "local"
fmt.Println(l)
fmt.Println(g)
}
func main() {
printLocal()
fmt.Println(g)
}
Outputlocal
global
global
Начнем с объявления глобальной переменнойg
,var g = "global"
. В функцииmain
мы вызываем функциюprintLocal
, которая объявляет локальную переменнуюl
и выводит ее,fmt.Println(l)
. ЗатемprintLocal
распечатывает глобальную переменнуюg
,fmt.Println(g)
. Несмотря на то, чтоg
не был определен вprintLocal
, к нему можно было получить доступ, поскольку он был объявлен в глобальной области. Наконец, функцияmain
также выводитg
.
Теперь давайте попробуем вызвать локальную переменную вне функции:
package main
import "fmt"
var g = "global"
func printLocal() {
l := "local"
fmt.Println(l)
}
func main() {
fmt.Println(l)
}
Outputundefined: l
Мы не можем использовать локальную переменную вне функции, для которой она назначена. Если вы попытаетесь это сделать, при компиляции вы получите ошибкуundefined
.
Давайте посмотрим на другой пример, где мы используем одно и то же имя переменной для глобальной переменной и локальной переменной:
package main
import "fmt"
var num1 = 5
func printNumbers() {
num1 := 10
num2 := 7
fmt.Println(num1)
fmt.Println(num2)
}
func main() {
printNumbers()
fmt.Println(num1)
}
Output10
7
5
В этой программе мы дважды объявили переменнуюnum1
. Сначала мы объявилиnum1
в глобальной области видимости,var num1 = 5
, и снова в локальной области действия функцииprintNumbers
,num1 := 10
. Когда мы печатаемnum1
из программыmain
, мы видим распечатанное значение5
. Это потому, чтоmain
видит только объявление глобальной переменной. Однако, когда мы выводимnum1
из функцииprintNumbers
, она видит локальное объявление и распечатывает значение10
. Несмотря на то, чтоprintNumbers
создает новую переменную с именемnum1
и присваивает ей значение10
, это не влияет на глобальный экземплярnum1
со значением5
с.
При работе с переменными вам также необходимо учитывать, каким частям вашей программы потребуется доступ к каждой переменной; принятие глобальной или локальной переменной соответственно. В программах Go вы обнаружите, что локальные переменные обычно более распространены.
Константы
Константы похожи на переменные, за исключением того, что они не могут быть изменены после того, как они были объявлены. Константы полезны для определения значения, которое будет использоваться в вашей программе более одного раза, но не может быть изменено.
Например, если мы хотим объявить ставку налога для системы корзины покупок, мы можем использовать константу, а затем рассчитать налог в разных областях нашей программы. В какой-то момент в будущем, если налоговая ставка изменится, нам нужно будет изменить это значение только в одном месте нашей программы. Если бы мы использовали переменную, вполне возможно, что мы могли бы случайно изменить значение где-то в нашей программе, что привело бы к неправильным вычислениям.
Чтобы объявить константу, мы можем использовать следующий синтаксис:
const shark = "Sammy"
fmt.Println(shark)
OutputSammy
Если мы попытаемся изменить константу после ее объявления, мы получим ошибку во время компиляции:
Outputcannot assign to shark
Константы могут бытьuntyped
. Это может быть полезно при работе с числами, такими как данные целочисленного типа. Если константаuntyped
, она явно преобразуется, а константыtyped
- нет. Давайте посмотрим, как мы можем использовать константы:
package main
import "fmt"
const (
year = 365
leapYear = int32(366)
)
func main() {
hours := 24
minutes := int32(60)
fmt.Println(hours * year)
fmt.Println(minutes * year)
fmt.Println(minutes * leapYear)
}
Output8760
21900
21960
Если вы объявите константу с типом, это будет именно этот тип. Здесь, когда мы объявляем константуleapYear
, мы определяем ее как тип данныхint32
. Следовательно, это константаtyped
, что означает, что она может работать только с типами данныхint32
. Константуyear
мы объявляем без типа, поэтому она считаетсяuntyped
. Из-за этого вы можете использовать его с любым целочисленным типом данных.
Когдаhours
был определен, этоinferred, что он был типаint
, потому что мы явно не указали ему типhours := 24
. Когда мы объявилиminutes
, мы явно объявили его какint32
,minutes := int32(60)
.
Теперь давайте рассмотрим каждый расчет и почему он работает:
hours * year
В этом случаеhours
- этоint
, аyears
- этоuntyped. Когда программа компилируется, она явно преобразуетyears
вint
, что позволяет успешно выполнить операцию умножения.
minutes * year
В этом случаеminutes
- этоint32
, аyear
- этоuntyped. Когда программа компилируется, она явно преобразуетyears
вint32
, что позволяет успешно выполнить операцию умножения.
minutes * leapYear
В этом случаеminutes
- этоint32
, аleapYear
- это константаtyped дляint32
. На этот раз компилятору нечего делать, поскольку обе переменные уже одного типа.
Если мы попытаемся умножить два несовместимых типаtyped
, программа не скомпилируется:
fmt.Println(hours * leapYear)
Outputinvalid operation: hours * leapYear (mismatched types int and int32)
В этом случаеhours
выводился какint
, аleapYear
был явно объявлен какint32
. Поскольку Go является типизированным языком, символыint
иint32
несовместимы для математических операций. Чтобы их умножить, вам понадобитсяto convert one to a int32
or an int
.
Заключение
В этом уроке мы рассмотрели некоторые из распространенных случаев использования переменных в Go. Переменные являются важным строительным блоком программирования, служа символами, которые обозначают значение типа данных, который мы используем в программе.