Go学习笔记 - 基本结构
Changelogs
2021-06-11
更新分类、标签
基本结构
package main
import "fmt"
// 变量
// 函数
func main(){
fmt.Println("Hello Go")
}
- 每一个.go的文件以package声明开头,表名文件属于哪个包
- package 声明后面是import声明
- 然后是包级别的类型、变量、常量、函数的声明,不区分顺序
- main函数代表入口函数,固定写法
名称规范
- 名称的开头是一个字母(Unicode 中的字符即可)或下划线,后面可以跟任意数量的字符、数字和下划线,并区分大小写
- 名称以大写字母开头,是可以被外部使用的(导出),意味着对包外是可见和可访问的
- 采用“驼峰式”风格命名,而不是下划线。
- 有25个关键字
break default func interface select
case defer go map struct
chan else goto package switch
const if range type fallthrough
contine for import return var
变量
声明
使用关键字var声明变量。
var name type = expression
// 例如
var name string = "张三"
// 短变量声明, 使用 := 自动推导结果到变量
name := expression
// 例如
name := "李四"
类型
整数
Go 同时具备有符号整数和无符号整数,有符号可以理解为:支持表示正负数,无符号可以理解为全是正数。
有符号整数分4种大小:8位、16位、32位、64位,用int8、int16、int32、int64表示,对应的无符号整数是uint8、uint16、uint32、uint64。
还有两种类型int和uint。在特定的平台上,其大小与原生的有符号整数/无符号整数相同,或等于该平台上的运算效率最高的值。这两种类型大小相等,都是32位或者64位,具体大小由编译器决定。
rune类型是int32类型的同义词,常常用于指明一个值是Unicode码点(code point)。这两个名称可以互相使用。同样,byte类型是unit8类型的同义词,强调一个值是原始数据,而非量值。
还有一种无符号整数 uintptr,大小不明确,可以用于保存指针类型。仅用于底层编程。
浮点数
Go具有两种大小的浮点数,float32 和 float64。可以通过math包的math.MaxFloat32 和 math.MaxFloat64 常量来查看两种类型的最大值。
十进制情况下,float32的有效数字大约是6位,float64的有效数字大约是15位。
var f float32 = 2.3453
// 支持小数点前后不写
var f1 float32 = .234
var f2 float32 = 2344.
// 非常大或非常小的数字使用科学记数法,在数量级指数前写字母e或E
const Avogadro = 6.0214553e23
const Planck = 5.73245345e-34
复数
Go 具备两种大小的复数 complex64 和 complex128,二者分别由float32和float64构成。内置的complex函数根据给定的实部和虚部创建复数,内置的real函数和imag函数分别提取复数的实部和虚部。
var x complex128 = complex(1,2)
指针
- 指针的值是一个变量的地址。
- 使用&符(取地址操作符)获取一个变量的指针
- 使用*获取指针所指的向变量
- 指针是可以比较的,两个指针当且仅当指向同一个变量或者两者都是nil的情况下才相等。
new 函数
- 内置的new函数是另一种创建变量的方式
- 表达式new(T)创建一个未命名的T类型变量,初始化为T类型的零值,并返回其地址(*T)
- new函数和直接创建变量的唯一区别就是new函数不需要声明一个变量,而是直接返回了其指针
- new函数一种语法上的便利,不是基础概念
- new是一个预声明函数,不是一个关键字,支持被覆盖
变量的生命周期
- 生命周期指在程序执行过程中变量存在的时间段
- 变量的声明周期存在与该变量的外层执行区域
- 变量的声明周期通过指针等其他方式判断该变量是否可达(可以被访问),如果不可达,则被垃圾回收器收回
- 编译器会自动选择使用堆还是栈来给变量分配空间
- 当一个变量是局部变量时,默认会在栈上为变量分配空间。但是如果该变量最终可以在变量的声明周期外(外层执行区域)被访问,那么该变量会被创建在堆上。例如一个变量定义在函数中,但是在函数最后将该变量指针return到外部,那么该变量将创建在堆上,属于变量从函数逃逸。
- 在长生命周期对象中保持短生命周期对象不必要的指针,特别是全局变量中,会阻止垃圾回收器回收短变量,将会造成多余的内存消耗。
赋值
- 赋值使用赋值符:= 来将右边的表达式赋值给左边的变量
- 每一个算术和二进制操作符都有一个对应的赋值符,例如* 的赋值符是*=
多重赋值
- 多重赋值允许将几个变量一次性赋值, 例如 x , y = 2, 3
- 从风格上考虑,如果表达式复杂,则应避免使用多重赋值
可赋值性
- 类型精准:左变量和右边表达式结果值的类型要一致
- nil可以赋值给任何接口类型或引用类型变量
类型声明
使用type关键字声明命名类型,它和某个已有的类型使用相同的底层类型。语法如下
type name underlying-type
// 示例
// 定义一个摄氏度的类型
type Celsius float64
// 定义一个华氏度的类型
type Fahrenheit float64
- type定义的命名类型是一种语法和逻辑上的便利,方便使用相同底层类型控制不同的逻辑。
- 命名类型提供了类型转换:typeName(T) , 将T转换为typeName 类型
包和文件
- 每一个包给它的声明提供独立的命名空间
- 导入声明可以给导入的包定义一个短名称
- Go要求每一个导入的包都需要被使用,否则将在编译时报错
- 任何一个文件可以包含多个init() 函数,该函数用于初始化操作,不能被调用和引用。init() 函数会按照声明顺序自动执行。
- 包的初始化是按照依赖顺序进行的,每次初始化一个包。
// 方式1
import "fmt"
import "math"
// 方式2
import (
"fmt"
"math"
)
// 方式3:短名称(解决多个包名相同冲突问题
// 其中,使用. 代表直接可以调用,不需要用包名(不推荐)
import (
std "fmt"
. "math"
)