2.1 名称
关键字
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
预声明的常量、函数和函数
常量
- true、false、iota、nil
类型
- int、int8、int16、int32、int64
- unit、unit8、unit16、unit32、unit64、uintptr
- float32、float64、complex128、complex64
- bool、byte、rune、string、error
函数
- make、len、cap、new、append、copy、close、delete
- complex、real、image、panic、recover
实体第一个字母的大小写决定其可见性是否垮包
- 大写:对包外是可见和可访问的,即是可导出的
- 小写:只在被包中可见和可访问
包名
- 总是小写字母组成
- 驼峰式命名
2.2声明
- 声明给一个程序实体命名,并且设定其部分或全部属性
主要声明
- 变量 var
- 常量 const
- 类型 type
- 函数 func
2.3变量
- var 声明创建一个具体类型的变量,并给它附加一个名字,并设置它的初始值
通用形式
var name type = expression
- type(类型)和expression(表达式)只可省略一个
- 对应类型的零值
类型 | 零值 |
---|---|
int | 0 |
Boolean | false |
string | "" |
接口和引用类型(slice、指针、map、通道、函数) | nil |
复合类型(数组、结构体) | 零值是其所有元素或成员的零值 |
初始化
- 包级别的初始化在main 开始之前进行
- 局部变量初始化和声明一样在函数执行期间进行
- 变量可以通过返回多个值的函数进行初始化
短变量声明
- 短变量声明:用来声明和初始化局部变量
- 通用形式
- name := expression
- 一个多变量的声明不能和多重赋值搞混
- 如:i, j = j, i // 交换 i 和 j 的值
- i, j := 0, 1 //声明变量 i 和 j,并分别初始化为 0 和 1
- 短变量声明语句对已经声明过的变量(在同级词法域声明过的变量)只有赋值行为
- 短变量声明语句中必须至少要声明一个新的变量
指针
含义
- 指针的值是一个变量的地址(即该变量在内存中的存储位置)
- 每个变量必然有对应的内存地址,通过指针可直接读取或更新对应变量的值
- &变量名:取该变量的内存地址
- *指针名:读取指针指向的变量的值
- 任何类型的指针的零值都是nil
- 返回函数中局部变量的地址是安全的,如:
var p = f()
func f() *int {
v := 1
return &v
}
- 说明 :
- 函数 f() 创建局部变量 v,在局部变量地址返回后依然有效,因为指针 p 依然引用该变量,并且每次调用 f函数都会返回不同的结果
new函数
作用
- new 函数可以用来创建变量,如:
- new(T) 将创建一个T类型的匿名变量,初始化为T类型的零值,然后返回变量地址(即指针),返回的指针类型为 *T
- 每次new函数返回的都是一个新的变量的地址
变量的生命周期
含义
- 指的是在程序运行期间变量有效存在的时间段
- 是一个运行时的概念
变量 | 生命周期 |
---|---|
包级声明的变量 | 和整个程序的运行周期一致 |
局部变量(包括参数变量和返回值) | 动态生命周期:创建开始到不再被引用为止 |
决定因素
- 变量的有效周期只取决于它是否可达
分配局部变量的存储空间
- 编译器会自动选择在栈上还是堆上分配局部变量的存储空间
- 若变量没有从函数中逃逸,则可以选择在栈或堆(GC回收该变量的内存空间)上分配存储空间
- 若变量从函数中逃逸,则必须在堆上分配内存空间
2.4 赋值
赋值方式
命名变量的赋值
通过指针间接赋值
结构体字段赋值
数组、slice或map 的元素赋值
注:++或--是语句,不是表达式, x = i++ 是错误的
元组赋值
- 允许同时更新多个变量的值
可赋值性
- 基本规则:
- 类型必须完全匹配
- nil可以赋值给任何指针或引用类型的变量
2.5 类型
作用
- 类型定义了变量或表达式对应存储值的属性特征
声明类型
- type 类型名字 底层类型
- 该语句一般出现在包一级,若类型名字首字母大写,则表示在包外部也可以被使用
类型转换
T(x) 将值x转换为类型T,不是函数调用
命名类型的底层类型决定了它的结构、表达方式和它所支持的内部操作集合
命令类型的值可以与其相同类型的值进行比较,也可和底层类型相同的未命名类型的值进行比较,但不同命名类型的值不能直接比较
2.6 包和文件
包的作用
- 用于支持模块化、封装、编译隔离和重用
源代码
- 一个包的源代码保存在一个或多个以.go结尾的文件中
导入路径
- 包所在目录名的尾部
导入
- 每一个包给它的声明提供一个独立的命名空间
- 每一个包通过称为导入路径的唯一字符串来标识
包的初始化
init函数
- 任何文件可以包含任意数量的声明init的函数,如:
fun init(){}
-该init函数不能被调用和引用,在程序启动的时候该函数会按照它们声明的顺序自动执行
初始化顺序和过程
- 按照在程序中年导入的顺序来进行,依赖顺序优先,每次初始化一个包
- 初始化过程是自下向上的,main包最后初始化
2.7 作用域
定义
- 声明语句的作用域是指源代码中可以有效使用这个名字的范围
- 作用域对应的是一个源代码的文本区域
- 是编译时的属性
块(block)
- 句法块内部声明的名字是无法被外部访问的,即决定了内部声明的名字的作用域范围
词法块
- 全局词法块:对全局的源代码来说存在一个整体的词法块
- 对于每个包、for、if、switch、select等都有独立的词法块
- 词法块决定了作用域范围的大小
- 编译器从最内层的词法块向全局的作用域进行查找一个名字引用的定义
- 内部声明屏蔽外部同名的声明