顺序编程
1 变量
变量相当于是对一块数据存储空间的命名,程序通过定义一个变量来申请一块数据存储空间,之后通过引用变量名来使用这块存储空间
1.1 变量声明
Go语言引入关键字var来声明变量,类型放置在变量名后面
var v1 int
var v2 string
var v3 [10] int //数组
var v4 [] int //数组切片
var v5 struct {
f int
}
var v6 *int //指针
var v7 map[string] int //map,key为string ,value为int
var v8 func(a int) int
//var关键字可以将若个要声明的变量放在一起,免得程序重复写var关键字,如:
var (
v1 int
v2 string
)
1.2 变量初始化
对于声明变量时需要初始化的场景下,var关键字可以保留,但是不是必要的元素了
var v1 int = 10 //方式1,常规方法
var v2 = 10 //方式2,编译器会自动推导出v2的类型
v3 := 10 //方式3,编译器会自动推导出v3的类型,:= 左侧的变量不应该是已经被声明过的,否则会编译报错
//如下面会导致编译报错:no new variables on left side of :=
var a int
a := 2
:= 用于明确表达式同时进行变量声明和初始化的工作
1.3 变量赋值
Go语法中,变量初始化和变量赋值是两个不同的概念
// 下面为声明一个变量之后的赋值过程
var v10 int
v10 = 123
//下面为交换变量的语句
i, j = j, i
1.4 匿名变量
如函数返回了多个值,我们不想要其中的值时
_, _, nickName := GetName()
_ 表示忽略值,不会分配内存
2 常量
常量是指编译期间就已知且不可改变的值,常量可以是整型、浮点型、复数类型、布尔类型、字符串类型等
2.1 字面常量
常量,即为程序中硬编码的常量
-12 //整型常量
3.14159 //浮点型常量
3.12+12i //复数类型常量
true //布尔类型常量
"name" //字符串常量
2.2 常量定义
通过const关键字,可以给字面常量指定一个友好的名字
const Pi float64 = 3.14159265358
const zero = 0.0 //无类型浮点常量
const (
size int64 = 1024
eof = -1 //无类型整数常量
)
const u, v float32 = 0, 3 //常量的多重赋值
const a, b, c = 3, 4, "foo" // 无类型整型和字符串常量
常量定义可以是限定类型的,但不是必须的,如定义常量时没指定类型,那么它与字面常量一样,是无类型常量
常量的右值也可以是一个在编译期运算的常量表达式,比如
const mask = 1 << 3
但常量的赋值是一个编译期的行为,所以右值不能出现任何需要运行期才能得出结果的表达式,比如
const Home = os.GetEnv("HOME")
因为 os.GetEnv("HOME")
只有在运行期间才知道返回的结果,在编译期不能确定,所以无法作为常量定义的右值
2.3 预定义常量
Go语言预定义了这些常量:true、false、iota
iota 比较特殊,可以当成是一个被编译期修改的常量,在每一个const关键字出现时被重置为0,然后在下一个const出现之前,每出现一次iota,其所代表的数字就会自动增1
const ( //iota被重设为0
c0 = iota // c0 == 0
c1 = iota // c1 == 1
c2 = iota // c2 == 2
)
const(
a = 1 << iota // a == 1, (iota在每个const开头被重设为0) 「0000 0001 像左移0位」
b = 1 << iota // b == 2, (iota=1)「0000 0001 向左移1位变为 0000 0010」
c = 1 << iota // c == 4, (iota=2)「0000 0001 向左移2位变为 0000 0100」
)
const (
u = iota * 42 // u == 42
v float64 = iota * 42 // v == 42.0
w = iota * 42 //w == 84
)
如果两个const赋值语句表达式一样,可以省略写法
const ( //iota被重设为0
c0 = iota // c0 == 0
c1 // c1 == 1
c2 // c2 == 2
)
const (
a = 1 << iota // a == 1, (iota在每个const开头被重设为0) 「0000 0001 像左移0位」
b // b == 2, (iota=1)「0000 0001 向左移1位变为 0000 0010」
c // c == 4, (iota=2)「0000 0001 向左移2位变为 0000 0100」
)
2.4 枚举
枚举是指一系列相关的常量,比如一个星期中每天的定义
const (
Sundat = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Satirdau
Saturday
numberOfDays // 此常量没有导出
)
// 以大写字母开头的常量在包外可见,numberOfDays为包内私有,其他常量则可以被其他包访问
3 类型
Go语言中内置了以下基础类型
- 布尔类型:bool
- 整型:int8、byte、int16、int、unit、unitptr
- 浮点类型:float32、float64
- 复数类型:complex64、complex128
- 字符串:string
- 字符类型:rune
- 错误类型:error
和以下复合类型
- 指针:pointer
- 数组:array
- 数组切片:slice
- 字典:map
- 通道:chan
- 结构体:strut
- 接口:interface
3.1 布尔类型
Go语言中的布尔类型与其他语言一致,关键字也为bool,可赋予的值为 true和false
var v1 bool
v1 = true
v2 := (1 == 2) // v2也会被推导为bool类型
布尔类型不接受其他类型的赋值,不支持自动或强制的类型转换,以下是错误用法
var b bool
b = 1 // 编译报错
以下的用法才是正确的
var b bool
b = (1 != 0) //编译正确,b==true
3.2 整型
整型是所有编程语言中最基础的数据类型,Go支持下列这些整型类型
- int8 范围:-128 ~ 127
- unit8(即byte) 范围:0 ~ 255
- int16 范围:-32768 ~ 32767
- unit16 范围:0 ~ 65535
- int32 范围:-2 147 483 648 ~ 2 147 483 647
- unit32 范围:0 ~4 294 967 295
- int64 范围:-9 233 372 036 854 775 808 ~ 9 233 372 036 854 775 807
- unit64 范围:0 ~ 18 446 744 073 709 551 615
- int 范围:与平台相关
- unit 范围:与平台相关
- unitptr 范围:32位平台下为4字节,64位平台下为8字节
3.2.1 类型表示
需要注意的是int和int32在Go语言中被认为是两种不同的类型,编译器不会帮你自动做类型转换,下列情况会编译报错
var value2 int32
value1 := 64 //value1将会被自动推导为int类型
value2 = value1 //编译报错
// 报错信息:cannot user value1 (type int) as type int32 in assignment
使用强制类型转换可以解决这个编译报错
value2 = int32(value1) // 编译通过
3.2.2 数值运算
Go语言支持常规运算:+,-,*,/ 和 % ,就不解释了,需要说明下 %表示取余
5 % 3 // 结果为 2
3.2.3 比较运算
Go语言支持的比较运算符:>, <, == , >=, <= 和 != 基本与其他语言一致,就不解释了,需要说明下的是,Go语言的两个不同类型的整型数是不能直接比较的,比如int8类型的数不能和int类型的数直接比较,但各种类型下的整型变量可以与字面常量进行比较,比如
var i int32
var j int64
i, j = 1, 2
if i == j { // 编译报错
...
}
if i == 1 || j == 2 { // 编译通过
...
}
3.2.4 位运算
124 << 2 // 496, 124的二进制向左移2位
124 >> 2 // 31, 124的二进制向右移2位
124 ^ 2 // 126, 异或,相同为1,不同为0
124 & 2 // 0, 与,都为1时为1,否则为0
124 | 2 //126, 或,只要有一个1就为1,否则为0
^2 // -3, 取反,标识位也取反 010 -> 101, 101 -> -101 ,故为-3
3.3 浮点类型
浮点型表示包含小数点的数据,Go语言中浮点类型采用的是IEEE-754标准的表达方式
3.3.1 浮点数表示
var fvalue1 float32
fvalue1 = 12
fvalue2 := 12.0 //如果不加小数点,fvalue2会被推导为整型,该浮点变量将被自动转为float64
fvalue1 = fvalue2 //将会报错,需要进行下列强制转换
fvalue1 = float32(fvalue2)
3.3.1 浮点数比较
因浮点数不是一种精确的表达方式,直接用 == 来判断是不可行的,可能导致不稳定的结果,下面是替代方案
import "math"
func IsEqual(f1, f2, p float64) bool {
retrun math.Abs(f1-f2) < p
}
3.4 复数类型
复数实际上是由两个实数(计算机中用浮点数表示)构成,一个表示实部(real),一个表示虚部(image)
3.4.1 复数表示
var value1 complex64 //由2个float32构成的复数类型
value1 = 3.2 + 12i
value2 := 3.2 + 12i // value2 是complex128类型
value3 = complex(3.2, 12) // value3结果同 value
3.4.2 实部与虚部
z = complex(x, y) //复数
x = reala(z) // 通过内置函数获取实部x
y = imag(z) // 通过内置函数获取虚部y
3.5 字符串
Go语言中字符串的声明和初始化非常简单
var str string // 声明一个字符串变量
str = "Hello Word" // 字符串赋值
ch := str[0] // 获取字符串的第一个字符
字符串可以类似于数组,通过下标获取内容,但字符串的内容不可以在初始化之后被修改,如下会编译报错
str := "Hello Word"
str[0] = h // 编译报错:cannot assigin to str[0]
3.5.1 字符串操作
"hello" + "word" // 结果为 helloword,字符拼接
len(hello) //结果为5,获取字符串长度
"hello"[1] //结果为e,获取字符
3.5.2 字符串遍历
Go语言支持两种方式遍历字符串
一种是以字节数组的方式遍历
str := "Hello, 世界"
n := len(str)
for i := 0; i < n; i++ {
ch := str[i] //根据下标取字符串的字符,ch类型为byte
fmt.Println(i, ch)
}
输出结果:
0 72
1 101
2 108
3 108
4 111
5 44
6 32
7 228
8 184
9 150
10 231
11 149
12 140
// 字符长度实际是13,因每个中文占3个字节,而不是1个字节
另一种是以Unicode字符遍历
str := "Hello, 世界"
for i,ch := range str {
fmt.Println(i, ch) //ch的类型为rune
}
输出结果:
0 72
1 101
2 108
3 108
4 111
5 44
6 32
7 19990
10 30028
// 以Unicode字符方式遍历时,每个字符的类型是rune
3.6 字符类型
Go语言中支持两个字符串的类型
一个是byte(实际是unit8的别名),代表UTF-8字符串的单个字节的值,另一个是rune,代表单个Unicode字符
标准库unicode包中提供了UTF8和Unicode之间的转换
Go语言多少API都假设字符串为UTF-8编码,尽管Unicode字符在标准库中有支持,但实际上较少使用。
3.7 数组
数组是Go语言编程中最常用的数据结构之一,数组长度在定义后就不可更改
声明方法
[32]byte // 长度为32的数组,每个元素为一个字节
[2*N] struct {x, y int32} //复杂类型数组
[1000]*float64 // 指针数组
[3][5] int // 二维数组,表示3行5列的二维数组
[2][2][2] float64 // 等同于 [2]([2]([2]float64))
3.7.1 元素访问
for i := 0; i < len(array); i++ {
fmt.Println(array[i])
}
for i, v := rang array { // i表示下标,v表示值
fmt.Println(v)
}
3.7.2 值类型
在Go语言中数组是一个值类型 (value type)