一、简介
Go 语言声明变量一般使用 var
关键词,例如:
// var identifier type
var name string
需要注意的是,Go 和许多编程语言不同,它在声明变量时将变量的类型放在变量的名称之后。这样做的目的就是为了避免像 C 语言中那样含糊不清的声明形式,例如:int* a, b;
。在这个例子中,只有 a
是指针而 b
不是。如果你想要这两个变量都是指针,则需要将它们分开书写。而在 Go 中,则可以很轻松地将它们都声明为指针类型:
var a, b *int
除此之外这种语法能够按照从左至右的顺序阅读,使得代码更加容易理解。
二、声明示例
var a int
var b bool
var str string
因式分解关键字
var (
a int
b bool
str string
)
提示
这种因式分解关键字的写法一般用于声明全局变量。
三、默认值
当一个命令被声明之后,系统会自动赋予它该类型的零值,下面是所有常见类型对应的零值:
类型 | 默认值 |
---|---|
int |
0 |
float32(64) |
0.0 |
bool |
false |
string |
"" |
指针 |
nil |
记住,所有的内存在 Go 中都是经过初始化的。
四、命名规范
变量的命名规则遵循骆驼命名法,即首个单词小写,每个新单词的首字母大写,例如:numShips
和 startDate
。
提示
如果你的全局变量希望能够被外部包所使用,则需要将首个单词的首字母也大写
五、作用域
一个变量(常量、类型或函数)在程序中都有一定的作用范围,称之为作用域。如果一个变量在函数体外声明,则被认为是全局变量,可以在整个包甚至外部包(被导出后)使用,不管你声明在哪个源文件里或在哪个源文件里调用该变量。
5.1 函数体中的变量
在函数体内声明的变量称之为局部变量,它们的作用域只在函数体内,参数和返回值变量也是局部变量。
5.2 控制结构中的变量
控制结构中声明的变量的作用域只在相应的代码块内,一般情况下,局部变量的作用域可以通过代码块(用大括号括起来的部分)判断。
尽管变量的标识符必须是唯一的,但你可以在某个代码块的内层代码块中使用相同名称的变量,则此时外部的同名变量将会暂时隐藏(结束内部代码块的执行后隐藏的外部同名变量又会出现,而内部同名变量则被释放),你任何的操作都只会影响内部代码块的局部变量。
通常声明局部变量时,应使用简短声明语法
:=
,例如:
a := 1
六、值类型和引用类型
程序中所用到的内存在计算机中称为 “字”,它是用于表示自然数据单位的术语。字由固定长度的位(Bit)组成,一个字的位数(即字长)通常是32位(4字节)或64位(8字节);所有的字都使用相关的内存地址来进行表示(以十六进制数表示)。
6.1 值类型
所有像 int
、float
、bool
和 string
这些基本类型都属于值类型,使用这些类型的变量直接指向存在内存中的值。像数组和结构这些复合类型也是值类型。
当使用等号 =
将一个变量的值赋值给另一个变量时,如:j = i
,实际上是在内存中将 i
的值进行了拷贝。
通过 &
来获取一个一个变量的内存地址,例如:&i
=> 0xf840000040
(每次的地址都可能不一样)。
值类型的变量的值存储在栈中。
内存地址会根据机器的不同而有所不同,甚至相同的程序在不同的机器上执行后也会有不同的内存地址。因为每台机器可能有不同的存储器布局,并且位置分配也可能不同。
6.2 引用类型
更复杂的数据通常会需要使用多个字,这些数据一般使用引用类型保存。一个引用类型的变量 r1
存储的是 r1
的值所在的内存地址(数字),或内存地址中第一个字所在的位置。
这个内存地址被称之为指针,这个指针实际上也被存在另外的某一个字中。
同一个引用类型的指针指向的多个字可以是在连续的内存地址中(内存布局是连续的),这也是计算效率最高的一种存储形式;也可以将这些字分散存放在内存中,每个字都指示了下一个字所在的内存地址。
当使用赋值语句 r2 = r1
时,只有引用(地址)被复制;如果 r1
的值被改变了,那么这个值的所有引用都会指向被修改后的内容,在这个例子中,r2
也会受到影响。
在 Go 中,指针、slices、maps、channel 都属于引用类型,被引用的变量会存储在堆中,以便进行垃圾回收,且比栈拥有更大的内存空间。