Go语言基础语法,Go在很多特性上和C非常相近。
标识符
编程语言中标识符实际上是程序员定义的具有特殊意义的名称,比如变量名、常量名、函数名等。
- Golang中标识符有字母、数字、下划线三部分组成,同时只能以字母或下划线开头。
- Golang推荐使用驼峰法命名
关键字
- 关键字是指编程语言中预先定义好且具有特殊含义的标识符
- 关键字和保留字不建议作为变量名
- 函数外的每个语句都必须以关键字开头
Golang中拥有25个关键字和37个保留字。
变量
程序运行过程中数据都是保存在内存中的,若要在代码中操作某个数据就需要去内存上寻找对应变量。若直接在代码中通过内存地址去操作变量,代码的可读性会非常差且容易出错。利用变量可将数据的内存地址保存起来,日后可直接使用变量即可找到内存上与之对应的数据了。
变量声明
- 非全局变量必须先声明再使用
变量在数学概念中表示没有固定值且可改变的数,在计算机系统实现中变量则是一段或多段用来存储数据的内存。
Go是静态类型语言,因此变量需要明确类型,因为编译器会检查变量类型的正确性。
变量声明方式
标准声明方式
使用var name type声明变量时以关键字var开头,后置变量类型,行尾无需分号。
var name type
- Go变量声明中,
var是声明变量的关键字,name表示变量名,type表示变量类型。 - Go在声明变量时需将变量类型放在变量名之后,以避免类似C语言中含糊不清的声明形式。
//C语言声明变量指针
int* a, b;
//Go语言声明变量指针
var a,b *int
短变量声明
- short variable declaration
- 使用
name := expression( 变量名:=表达式)简短形式时,用于变量定义同时显式初始化。 - 短变量声明简短形式不能提供数据类型,只能用在函数体中,即
:=不能使用在函数外。 - 由于短变量声明简洁且灵活的特定,简短变量声明广泛用于局部变量中。
-
var声明形式往往用于需要显式指定变量类型或因变量稍后会被重新赋值而初始值无关紧要的地方
func main() {
x := 0
}
简短形式可声明和初始化一组变量
i,j := 0,1
批量声明
使用var关键字和小括号()可以将一组变量定义放在一起,用于批量声明。
var (
id int
name string
score []float32
job struct {
post string
}
lock func() bool
)
变量初始化
- 声明变量同时赋值
变量初始化标准格式
var 变量名 数据类型 = 表达式
比如:游戏玩家初始血量为100
var hp int = 100
Go在声明变量时会自动对变量相应的内存空间进行初始化操作,初始化为对应数据类型的默认值。
| 数据类型 | 默认值 |
|---|---|
| 整型变量 | 0 |
| 浮点型变量 | 0.0 |
| 字符串变量 | 空字符串 |
| 布尔型变量 | 假false
|
| 指针、函数、切片变量 | nil |
编译器类型推导
在变量初始化标准格式的基础上,编译器会尝试根据等号右边的表达式(编译原理中称之为右值rvalue)推导变量的数据类型。
package main
import (
"fmt"
)
func main() {
var hp = 100
var defence = 20
var damageRate float32 = 0.15
var damage = float32(hp-defence) * damageRate
fmt.Println(hp, defence, damageRate, damage)
}
Go中编译器为了尽量提高精确度以避免计算中的精度损失,默认会将浮点数转换为float64,可强制指定浮点数的类型为float32。
使用简短方式声明变量,实质上正是推导声明的写法,编译器会自动根据右值推导出左值的数据类型。如果变量已经被声明过再次使用:=类型推导声明则会报错,因为推导声明写法中左值必须是没有定义过的变量。若已经定义过则会发生编译错误。
conn, err := net.Dial("tcp", "127.0.0.1:8080")
不过需要注意的是在多个变量声明和赋值中,只要至少有一个新变量的声明出现在左值中,那么即使其它变量名可能出现重复,编译器是不会报错的。
conn, err := net.Dial("tcp", "127.0.0.1:8080")
conn1, err := net.Dial("tcp", "127.0.0.1:8080")
匿名变量
匿名变量即没有名称的变量,编码中使用没有名称的变量、类型或方法可以增强代码的灵活性。在Lua等变成语言中,匿名变量又称为哑元变量。
- 匿名变量使用下划线
_,下划线本身是一个特殊的标识符,即空白标识符。 - 使用匿名变量时只需要在变量声明的位置使用
_下划线替代即可 - 空白标识符可以像其他标识符一样用于变量声明或赋值
- 空白标识符可赋予任何类型的值,但值都会被抛弃,其值并不能在后续代码中使用。
- 空白标识符作为变量时,禁止使用它对其它变量进行赋值和运算。
- 匿名变量不会占用内存空间,不会为其分配内存。
- 匿名变量与匿名变量之间也不会因为多次声明而无法使用
- 匿名变量多用于占位表示忽略值
func test() (int, int){
return 1, 2
}
func main() {
x, _ := test()
_, y := test()
fmt.Println(x, y)//1 2
}
多重赋值
编码中变量交换往往需要中间变量进行临时保存,早期计算机内存资源精贵,变量交换非常奢侈。到了Go语言时内存不再是稀缺资源,为了精简写法,可使用Go提供的多重赋值完成变量交换的任务。
变量交换算法
var x int = 100
var y int = 200
var z int
z = x
x = y
y = z
fmt.Println(x, y, z)//200 100 100
避免使用中间变量
var x int = 100
var y int = 200
x = x ^ y
y = y ^ x
x = x ^ y
fmt.Println(x, y)//200 100
Go多重赋值实现变量交换
var x int = 100
var y int = 200
x,y = y,x
fmt.Println(x, y)//200 100
多重赋值时变量的左值和右值按从左到右的顺序赋值
多重赋值在错误处理和函数返回值中会大量使用,比如排序时使用多重赋值。
// 声明[]int类型的整型切片类型
type IntSlice []int
//为整型切片类型的数据提供切片长度方法
func (data IntSlice) Len() int { return len(data) }
//获取整型切片中较小元素
func (data IntSlice) Less(i, j int) bool { return data[i] < data[j] }
//交换整型切片数组中元素的值
func (data IntSlice) Swap(i, j int) { data[i], data[j] = data[j], data[j]}
变量作用域
变量的作用域即变量(常量、类型、函数)在程序中的作用范围,Go语言在编译时会检查每个变量是否使用过,一旦出现未使用过的变量则会报出编译错误。
根据变量定义的位置,可将变量分为三类,每类变量的作用域互不相同。
- 局部变量:函数内定义的变量
- 全局变量:函数外定义的变量
- 形式参数:函数定义中的变量
局部变量
- 局部变量在函数体内定义,其作用域只在函数体内有效,函数参数和返回值都数据局部变量。
- 局部变量只有在函数被调用后才会存在,调用结束时局部变量会被销毁。
var x int = 1
var y int = 2
result := x + y
fmt.Printf("x = %d, y = %d, result = %d\n", x, y, result)
全局变量
- 全局变量在函数外声明即全局变量只需要在源文件中定义就可以在所有源文件中使用。
- 不包含全局变量的源文件需使用
import关键引入后方可使用 - 全局变量声明必须以
var关键字开头,外部包使用的全局变量首字母必须大写。 - 当局部变量与全局变量同名时局部变量会被优先使用
//声明全局变量
var pi float32 = 3.14
func main(){
//声明局部变量
var pi int = 100
fmt.Println(pi)//100
}
形式参数
- 函数定义时函数名后小括号内的变量称为形式参数(形参)
- 形式参数只有在函数调用时才会生效,函数调用结束时会被销毁。
- 函数未被调用时形参不占用实际的存储单元即无实际值
- 形式参数可作为函数的局部变量使用
func sum(x, y int) int{
result := x + y
return result
}
func main(){
var x int = 1
var y int = 2
z := sum(x, y)
fmt.Printf("x = %d, y = %d, z = %d", x, y, z)
}
变量逃逸
堆(heap)
- 堆是用于存放进程执行期间被动态分配的内存段
- 堆的大小并不固定,可动态扩张或缩减。
- 当进程调用
malloc等函数分配内存时,新分配的内存会被动态的添加到堆上。 - 当进程调用
free等函数释放内存时,被释放的内存会从堆中被剔除。
栈(stack)
- 栈又称为堆栈,是用于存放程序暂时创建的局部变量。
程序编译阶段,编译器会根据实际情况自动选择在堆或栈上分配局部变量的存储空间,不论是使用var还是new关键字声明的变量都不会影响编译器的选择。
变量的逃逸行为发生时,逃逸的变量需要额外的分配内存,对性能优化可能会产生细微的影响。
生命周期
变量的生命周期是指程序运行期间变量有效存在的时间间隔
虽然Go能够帮助完成内存的分配和释放,但为了开发出高性能的应用,仍需要了解变量的声明周期。若将局部变量赋值给全局变量将会阻止垃圾回收器对局部变量的收回,导致不必要的内存占用,从而影响程序的性能。
变量的生命周期与变量的作用域有着密不分割的关系
- 局部变量:局部变量的生命周期是动态的,从创建变量的声明语句开始到变量不再被引用为止。
- 全局变量:全局变量的生命周期和整个程序的运行周期保持一致
- 形式参数和函数返回值:形式参数和函数返回值均属于局部变量,在函数被调用时创建,函数调用结束后被销毁。
变量类型
Go语言中常见的基础数据类型包括:
| 数据类型 | 描述 | 初始值 |
|---|---|---|
| bool | 布尔值 | false |
| string | 字符串 | 空字符串""
|
| int/int8/int16/int32/int64/ | 整型 | 0 |
| uint/uint8/uint16/uint32/uint64 | 无符号整型 | 0 |
| byte | uint8别名 | 0 |
| rune | int32别名表示Unicode码 | 0 |
| float32/float64 | 浮点数 | 0.0 |
| complex64/complex128 | 复数 | 0.0 |
- Go中变量声明后系统会自动赋予对应数据类型的初始值
- Go中变量命名规则遵循驼峰法,首单词小写其后每个新单词首字母大写,比如
startDate、numUser...









网友评论