Переменные в языке Go
Переменные возникли в математике; в компьютерных языках это абстрактные понятия, которые могут хранить результаты вычислений или представлять значения.
Доступ к переменным можно получить через их имена.
Имена переменных в Go состоят из букв, цифр и символов подчёркивания, причём первый символ не может быть цифрой.
Общая форма объявления переменной — использование ключевого слова var:
var identifier type
Можно объявить несколько переменных одновременно:
var identifier1, identifier2 type
Пример
import "fmt"
func main() {
var a string = "Example"
fmt.Println(a)
var b, c int = 1, 2
fmt.Println(b, c)
}
Вывод приведенного выше примера:
Example 1 2
Объявление переменной
Сначала укажите тип переменной. Если она не инициализирована, переменная по умолчанию принимает своё нулевое значение.。
var v_name v_type v_name = value
Нулевое значение — это значение, устанавливаемое системой по умолчанию, когда переменная не была инициализирована.
Пример
import "fmt"
func main() {
// Объявить переменную и инициализировать её
var a = "EXAMPLE"
fmt.Println(a)
// Без инициализации — нулевое значение
var b int
fmt.Println(b)
// Нулевое значение bool — false
var c bool
fmt.Println(c)
}
Результат выполнения приведенного выше примера:
EXAMPLE 0 false
Числовые типы (включая complex64/128) равны0
-
Логический тип равенfalse
-
Строка — это""(пустая строка)
Следующие типы:nil:
var a *int var a []int var a map[string] int var a chan int var a func(string) int var a error // error 是接口
Пример
import "fmt"
func main() {
var i int
var f float64
var b bool
var s string
fmt.Printf("%v %v %v %q\n", i, f, b, s)
}
Вывод:
0 0 false ""
Во-вторых, тип переменной определяется самим значением.
var v_name = value
Пример
import "fmt"
func main() {
var d = true
fmt.Println(d)
}
Вывод:
true
В-третьих, если переменная уже была объявлена с помощью var, то повторное её использование:=для объявления переменной вызовет ошибку компиляции. Формат:
v_name := value
Например:
var intVal int intVal :=1 // 这时候会产生编译错误,因为 intVal 已经声明,不需要重新声明
Просто используйте следующую инструкцию:
intVal := 1 // 此时不会产生编译错误,因为有声明新的变量,因为 := 是一个声明语句
intVal := 1Эквивалентно:
var intVal int intVal =1
Вы можете сократить var f string = "Example" до f := "Example":
Пример
import "fmt"
func main() {
f := "Example" // var f string = "Example"
fmt.Println(f)
}
Вывод:
Example
Объявление нескольких переменных
//类型相同多个变量, 非全局变量
var vname1, vname2, vname3 type
vname1, vname2, vname3 = v1, v2, v3
var vname1, vname2, vname3 = v1, v2, v3 // 和 python 很像,不需要显示声明类型,自动推断
vname1, vname2, vname3 := v1, v2, v3 // 出现在 := 左侧的变量不应该是已经被声明过的,否则会导致编译错误
// 这种因式分解关键字的写法一般用于声明全局变量
var (
vname1 v_type1
vname2 v_type2
)
Пример
import "fmt"
var x, y int
var ( // Этот синтаксис с ключевым словом var обычно используется для объявления глобальных переменных
a int
b bool
)
var c, d int = 1, 2
var e, f = 123, "hello"
// Эта форма без синтаксиса объявления может появляться только внутри тела функции
//g, h := 123, "hello"
func main(){
g, h := 123, "hello"
fmt.Println(x, y, a, b, c, d, e, f, g, h)
}
Результат выполнения приведенного выше примера:
0 0 0 false 1 2 123 hello 123 hello
Типы значений и ссылочные типы
Все базовые типы, такие как int, float, bool и string, являются типами значений. Переменные этих типов напрямую указывают на значения, хранящиеся в памяти:
При использовании знака равенства=Когда вы присваиваете значение одной переменной другой переменной, например:j = iфактически она копирует значение i в памяти:
Вы можете получить адрес памяти переменной i с помощью &i, например: 0xf840000040 (адрес может быть другим каждый раз).
Переменные типов значений обычно хранятся в стеке, особенно когда они являются локальными переменными. Когда значение переменной типа значения должно использоваться вне области видимости функции, Go выделяет для него память в куче.
Адреса памяти могут различаться в зависимости от машины, и даже одна и та же программа может иметь разные адреса памяти после выполнения на разных машинах. Это связано с тем, что каждая машина может иметь различную разметку памяти, а распределение местоположений также может отличаться.
Более сложные данные обычно требуют нескольких слов, и такие данные, как правило, хранятся с использованием ссылочных типов.
Переменная ссылочного типа r1 хранит адрес памяти (число), по которому расположено значение r1, или позицию первого слова по этому адресу памяти.
Этот адрес памяти называется указателем, и этот указатель фактически хранится в некотором другом значении.
Несколько слов, на которые указывает указатель одного и того же ссылочного типа, могут находиться по последовательным адресам памяти (непрерывное размещение в памяти), что также является наиболее эффективной с точки зрения вычислений формой хранения; или же эти слова могут быть разбросаны по памяти, при этом каждое слово указывает адрес памяти следующего слова.
Когда используется оператор присваивания r2 = r1, копируется только ссылка (адрес).
Если значение r1 изменяется, то все ссылки на это значение будут указывать на изменённое содержимое. В этом примере на r2 это тоже повлияет.
Краткая форма с использованием оператора присваивания :=
Мы знаем, что при инициализации переменной тип переменной можно опустить, и система автоматически его выведет. Указывать ключевое слово var в операторе объявления несколько избыточно, поэтому можно сократить это до a := 50 или b := false.
Типы a и b (int и bool) будут автоматически выведены компилятором.
Это предпочтительная форма использования переменных, но её можно применять только внутри тела функции и нельзя использовать для объявления и присваивания глобальных переменных. Использование оператора := позволяет эффективно создать новую переменную; это называется объявлением с инициализацией.
Примечания
В одном и том же блоке кода нельзя снова использовать объявление с инициализацией для переменной с тем же именем. Например, a := 20 не допускается, и компилятор выдаст ошибку: no new variables on left side of :=, но a = 20 допускается, поскольку это присваивает новое значение той же переменной.
Если использовать переменную a до её определения, возникнет ошибка компиляции: undefined: a.
Если вы объявляете локальную переменную, но не используете её в том же блоке кода, вы также получите ошибку компиляции, например, переменная a в следующем примере:
Пример
import "fmt"
func main() {
var a string = "abc"
fmt.Println("hello, world")
}
Попытка скомпилировать этот код приведёт к ошибке.a объявлена, но не используется。
Кроме того, просто присвоить значение переменной a недостаточно; это значение должно быть использовано, поэтому используйте
fmt.Println("hello, world", a)Устранит ошибку.
Но глобальные переменные разрешено объявлять, не используя их.
var a, b, c int
Несколько переменных можно присвоить в одной строке, например:
var a, b int var c string a, b, c = 5, 7, "abc"
Приведённая выше строка предполагает, что переменные a, b и c уже объявлены; в противном случае её следует использовать так:
a, b, c := 5, 7, "abc"
Значения справа присваиваются переменным слева в том же порядке, поэтому значение a равно 5, значение b равно 7, а значение c равно "abc".
Это называется параллельным или одновременным присваиванием.
Если вы хотите поменять значения двух переменных, можно просто использоватьa, b = b, aтипы двух переменных должны совпадать.
Пустой идентификатор _ также используется для отбрасывания значений, например значения 5 в: _, b = 5, 7 отбрасывается.
_ на самом деле является переменной, доступной только для записи; вы не можете получить её значение. Это сделано потому, что в языке Go вы должны использовать все объявленные переменные, но иногда вам не нужно использовать все возвращаемые значения, полученные из функции.
Параллельное присваивание также используется, когда функция возвращает несколько значений. Например, здесь val и значение ошибки err получаются одновременно путём вызова функции Func1: val, err = Func1(var1).
Другие расширения