Go
-
go run xx.go
执行go文件 -
go build xx.go
生成二进制文件
一. GO 基础
1. 语言结构
- 包声明
- 每个Go文件都包含main的包
- 引入包
- 函数
- 变量
- 语句&表达式
-
{
不能单独放一行
-
- 注释
2. 基础语法
2.1 行分隔符
- 不需要以
;
结尾 - 若需要多个语句写在同一行,必须使用
;
-->不鼓励
2.2 注释
- 与JavaScript相同
-
//
单行注释 -
/* */
多行注释
2.3 标识符
- 不能以数字开头
- 不允许运算符
- 不使用关键字
2.4 关键字
关键字/保留字
预定义标识符
3. 数据类型
类型 | 描述 |
---|---|
布尔 | true/false |
数字类型 | int/float32、float64 |
字符串 | 使用UTF-8编码标记Unicode文本 |
派生类型 | 1. 指针<br />2. 数组<br />3. 结构化<br />4. Channel<br />5. 函数<br />6. 切片<br />7. 接口<br />8. Map |
3.1 数字类型
uint8 uint16 uint32 uint64 int8 int16 int32 int64
float32 float64 complex64 complex128
3.2 其他类型
byte rune uint int uintptr
4. 变量
-
使用
var
声明var a int = 10
var a =10
-
使用
:=
a := 10
不带声明格式的只能在函数体中出现
交换两个值的顺序
a, b = b, a
空白标识符
_
被用于抛弃值_
是一个只写变量,不能得到它的值
5. 常量
const identifier [type] = value
定义常量组时,若不提供初始值,则表示使用上行的表达式
5.1 iota
表示从0开始自动加1
<< n表示左移动,即转换为二进制数字往前移动n位数字,然后转换为十进制输出,也即 *2n
iota也只是在同一个const常量组内递增,有新的const关键字时,iota计数会重新开始
6. 运算符
-
算数运算符
- /
- %
- ++
-
关系运算符
- ==
- !=
- >
- <
- >=
- <=
-
逻辑运算符
- && AND
- || OR
- ! NOT
-
位运算符
- & 按位与
- | 按位或
- ^ 按位异或
-
赋值运算符
- =
- +=
- -=
- *=
- /=
- %=
- <<=
- >>=
- &=
- ^=
- |=
-
其他运算符
- & 取址
- * 指针变量
-
运算符的优先级
优先级 运算符 5 * / % << >> & &^ 4 + - | ^ 3 == != < <= > >= 2 && 1 ||
7. 条件语句
7.1 判断语句
// if语句
if 布尔表达式 {
/*code and code*/
}else{
/*code and code*/
}
// if嵌套
...
7.2 swith 语句
// switch语句
switch var1{
case val1:
...
case val2:
...
default:
...
}
- Type Switch
- 被用于type-switch 来判断某个interface变量中实际存储的变量类型。
- fallthrough
- 强制执行后边的case语句,无论下一个case表达式是否为true
7.3 select语句
select {
case communication clause :
statement(s);
case communication clause :
statement(s);
/* 可以定义任意数量的 case */
default : /* 可选 */
statement(s);
}
注意:Go 没有三目运算符,所以不支持 ?: 形式的条件判断。
8. 循环语句
8.1 for循环
和C语言的for一样 :
for init; condition; post {}
和C的while一样:
for condition{}
和C的for(;;)一样:
for{}
8.2 goto语句
goto label;
..
.
label: statement;
9. 函数
func function_name( [parameter list] ) [return_types] {
函数体
}
**默认情况下****,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数。
9.1 闭包
// go闭包示例
package main
import "fmt"
// 闭包使用方法,函数声明中的返回值(闭包函数)不用写具体的形参名称
func add(x1, x2 int) func(int, int) (int, int, int) {
i := 0
return func(x3, x4 int) (int, int, int) {
i += 1
return i, x1 + x2, x3 + x4
}
}
func main() {
add_func := add(1, 2)
fmt.Println(add_func(4, 5))
fmt.Println(add_func(1, 3))
fmt.Println(add_func(2, 2))
}
9.2 函数方法
func (variable_name variable_data_type) function_name() [return_type]{
/* 函数体*/
}
10. 变量作用域
- 函数内定义的变量称为局部变量
- 函数外定义的变量称为全局变量
- 函数定义中的变量称为形式参数
11. 数组
-
声明数组
var variable_name [SIZE] variable_type
-
初始化数组
var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0} balance := [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0} // 如果数组的长度不确定 var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0} //或 balance := [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0} // 将索引为 1 和 3 的元素初始化 balance := [5]float32{1:2.0,3:7.0}
12. 指针
取址符&
内存地址是一个16进制的数据
12.1空指针
当一个指针被定义后没有分配到任何变量时,它的值为 nil。
nil 指针也称为空指针
一个指针变量通常缩写为 ptr
12.2 指向指针的指针
var ptr **int;
13. 结构体
结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。
结构体的格式如下:
type struct_variable_type struct {
member definition
member definition
...
member definition
}
定义了结构体类型,就能用于变量的声明,格式如下:
variable_name := structure_variable_type {value1, value2...valuen}
或
variable_name := structure_variable_type { key1: value1, key2: value2..., keyn: valuen}
访问结构体成员
结构体.成员名
14. slice
定义切片:var identifier []type
切片不需要说明长度
使用make函数创建切片
var slice1 []type = make([]type, len)
//也可以简写为
slice1 := make([]type, len)
// 也可以指定容量,capacity为可选参数
mark([]T, length, capacity)
// 切片初始化
s := arr[startIndex:endIndex]
len() 方法获取长度。
cap() 方法测量切片最长可以达到多少
切片在未初始化之前默认为 nil
,长度为 0
如果想增加切片的容量,我们必须创建一个新的更大的切片并把原分片的内容都拷贝过来
拷贝切片的:copy 方法
向切片追加新元素的:append 方法
15. range
range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。在数组和切片中它返回元素的索引和索引对应的值,在集合中返回 key-value 对。
16. map
定义map
/* 声明变量,默认 map 是 nil */
var map_variable map[key_data_type]value_data_type
/* 使用 make 函数 */
map_variable := make(map[key_data_type]value_data_type)
如果不初始化 map,那么就会创建一个 nil map。nil map 不能用来存放键值对
17. 递归函数
递归,就是在运行的过程中调用自己
18. 类型转换
type_name(expression)
go 不支持隐式转换类型
19. 接口
/* 定义接口 */
type interface_name interface {
method_name1 [return_type]
method_name2 [return_type]
method_name3 [return_type]
...
method_namen [return_type]
}
/* 定义结构体 */
type struct_name struct {
/* variables */
}
/* 实现接口方法 */
func (struct_name_variable struct_name) method_name1() [return_type] {
/* 方法实现 */
}
...
func (struct_name_variable struct_name) method_namen() [return_type] {
/* 方法实现*/
}
20. 错误处理
// ErrorL类型是一个接口类型
type error interface {
Error() string
}
21. 并发
goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的。
go 函数名( 参数列表 )
同一个程序中的所有 goroutine 共享同一个地址空间。
通道
通道(channel)是用来传递数据的一个数据结构。
通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。操作符 <-
用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道
通道缓冲区
通道可以设置缓冲区,通过 make 的第二个参数指定缓冲区大小:
ch := make(chan int, 100)
带缓冲区的通道允许发送端的数据发送和接收端的数据获取处于异步状态,就是说发送端发送的数据可以放在缓冲区里面,可以等待接收端去获取数据,而不是立刻需要接收端去获取数据。
不过由于缓冲区的大小是有限的,所以还是必须有接收端来接收数据的,否则缓冲区一满,数据发送端就无法再发送数据了。
注意:如果通道不带缓冲,发送方会阻塞直到接收方从通道中接收了值。如果通道带缓冲,发送方则会阻塞直到发送的值被拷贝到缓冲区内;如果缓冲区已满,则意味着需要等待直到某个接收方获取到一个值。接收方在有值可以接收之前会一直阻塞。