Go基础--变量
变量
一、变量
1.1.变量声明
变量起名规则
- 理论上变量不限制长度
- 使用驼峰
- 局部变量(作用域小)的,使用短变量(比如i),作用域越大的,变量名称越长且有意义
基本的声明
1 |
|
可以省略type或者expression其中一个
- 省略type,自动推断类型
- 省略expression,使用该类型的默认值:如0、””、false;切片、指针、map、channel、函数,这些默认值是nil
通过var进行多个变量一起声明
1 |
|
短变量声明
1 |
|
- 短变量声明一般放在局部变量声明和初始化
- var声明变量
- 和初始化表达式类型不一致的局部变量
- 后边才对变量赋值的情况,变量初始值不重要的情况
注意点
在同一块作用域中不能声明两次变量
1 |
|
短变量声明的注意点
1 |
|
1.2.值类型的变量
所有像 int、float、bool 和 string 这些基本类型都属于值类型,使用这些类型的变量直接指向存在内存中的值
内存在计算机中用一堆箱子来表示,这些箱子被称为“字 (word)”
使用等号将一个变量的值赋给另一个的时候,实际上是在内存中的i值进行了拷贝
1 |
|
1.3.引用类型的变量
可以通过&i
来获取变量 i 的内存地址,例如:0xf840000040(每次的地址都可能不一样)。值类型的变量的值存储在栈中
引用类型的变量(上图中的r1)存储的是r1的值所在的内存地址,或者内存地址中第一个字(word)所在的位置。
这个内存地址被称为指针,这个指针实际上也被存在另外的某一个字中。
同一个引用类型的指针指向的多个字可以是在连续的内存地址中(内存布局是连续的),这也是计算效率最高的一种存储形式;也可以将这些字分散存放在内存中,每个字都指示了下一个字所在的内存地址。
当使用赋值语句 r2 = r1 时,只有引用(地址)的值被复制。
1.4.全局变量和局部变量
local_scope.go:
1 |
|
global_scope.go
1 |
|
function_calls_function.go
1 |
|
1.5.init函数中的变量
- 变量除了可以在全局声明中初始化,也可以在 init 函数中初始化。这是一类非常特殊的函数,它不能够被人为调用,而是在每个包完成初始化后自动执行,并且执行优先级比 main 函数高。
- 每个源文件都只能包含一个 init 函数。初始化总是以单线程执行,并且按照包的依赖关系顺序执行。
Init函数的用途:
在开始执行程序之前对数据进行检验或修复,以保证程序状态的正确性
设定某些固定的自定义全局变量
1
2
3
4
5
6
7
8
9package trans
import "math"
var Pi float64
func init() {
Pi = 4 * math.Atan(1) // init() function computes Pi
}当一个程序开始之前调用后台执行的 goroutine
1
2
3
4func init() {
// setup preparations
go backend()
}
1.6.变量的类型转换
go的类型转换必须要显示声明
1 |
|
具有相同底层类型的变量之间可以相互转换:
1 |
|
二、指针
2.1.指针、变量、值、地址的关系
- 指针的值,是一个变量的地址
- 每个变量都有地址,但是【值不一定有地址。怎么理解?】
- 使用一个指针引用一个值被称为间接引用(就是区别于直接引用变量)
2.2.指针的使用
- 一个指针变量可以指向任何一个值的内存地址 它指向那个值的内存地址,在 32 位机器上占用 4 个字节,在 64 位机器上占用 8 个字节。
指针demo
1 |
|
改变指针指向的值
1 |
|
不能获取字面量或常量的地址
1 |
|
- 指针的一个高级应用是你可以传递一个变量的引用(如函数的参数),这样不会传递变量的拷贝
- 指针传递是很廉价的,只占用 4 个或 8 个字节。当程序在工作中需要占用大量的内存,或很多变量,或者两者都有,使用指针会减少内存占用和提高效率
- 被指向的变量也保存在内存中,直到没有任何指针指向它们,所以从它们被创建开始就具有相互独立的生命周期。
- 指针也可以指向另一个指针,并且可以进行任意深度的嵌套,导致你可以有多级的间接引用,但在大多数情况这会使你的代码结构不清晰。
对一个空指针的反向引用是不合法的
1 |
|
三、new函数
new()方法创建一个未命名的T类型变量,初始化T类型零值,并返回其地址
1 |
|
new只是语法上的便利,以下两者是等价的:
1 |
|
通过new创建的两个变量的地址是不一样的
1 |
|
四、变量的生命周期
- 一个变量的生命周期就是从声明到不可访问
- go是自动垃圾回收的,垃圾回收的依据就是:变量是否可达
- 对于一些函数内/代码块里面的局部变量,执行完了,就会变得不可达(个人猜测)
- 对于全局的变量,存放在堆里面,局部的,存放在栈里面(个人理解)
4.1.逃逸
1 |
|
这样就算f执行完了,a是一个局部变量,但是还是可以通过global去找到a,这称为 a从f种逃逸。
五、作用域
- 作用域是编译时属性,是声明在程序文本中出现的区域
- 生命周期是运行时属性
- 语法块,词法块
Refs
- 《go程序设计》
- the way to go