原站地址:Go 语言教程 | 菜鸟教程
本文目的: 精简方式记录最重要的知识点,方便快速复习
一、基本语法
1. GO语言特点:高效,并行,开源,搭载Web服务器
2. 执行命令: go run hello.go
3. 编译命令: go build hello.go
4. 包声明: package main
5. 引入包: import "fmt"
6. 每行不需要分号结束;但一行多个语句的话,需要分号。
7. 声明变量方式一:用关键字 var,名字在前,类型在后。var b, c int = 1, 2
8. 声明变量方式二:a := 1, 相当于var a int = 1
9. 变量没有初始化,默认值分别是:0,false,"",nil (指针、切片,map)
10. 局部变量声明后不使用,会报错。但全局变量可以声明后不使用。
11. 交换两个变量的值:a, b = b, a
12. 并行复制可以用于函数返回,比如:val, err = Func1(var1)。
13. 可以通过 &i 来获取变量 i 的内存地址
14. 数据类型:
(1) 常规类型:bool,int,float32,,float64,string
(2) 派生类型:指针,数组,struct,Channel,函数,切片,接口,Map
(3) 其他类型:字节(byte),字符(rune), 无符号整型(uintptr)用于存放一个指针
15. 定义常量:const LENGTH int = 10
16. 定义枚举:(也是用的常量const关键字)
const (
Female = 1
Male = 2
)
17. 特殊常量 iota,在 const关键字出现时初始值是 0, 每新增一行常量声明将使 iota 计数一次. 且不受直接赋值操作的影响。
const (
a = iota //0
b //1
f = 100 //iota +=1
i //100 iota +=1
)
18. 枚举的每一行的运算规则,跟随上一行。比如下图, g跟随f,继续是100
const (
a = iota //0
b //1
f = 100
g //100
h = iota //4,恢复计数
i //5
)
19. 常量可以用len(), cap() 等 内置函数 计算表达式的值,但必须是内置函数。
20. 特殊运算符: <<左移, >>右移,^异或,&返回指针地址,*声明是指针
二、条件、循环语句
1. 包含: if, else if, else, switch case, select case
2. switch case :
switch var1 {
case a:
...
case b:
...
default:
...
}
(1) a 和 b 必须是相同数据类型, 但不被局限于常量或整数,可以是表达式。
(2) 从上至下逐一测试,直到匹配为止
(3) case 最后自带 break 语句,如果需要执行后面的 case,可以使用 fallthrough
3. select case:
select {
case <- channel1:
// 执行的代码
case value := <- channel2:
// 执行的代码
case channel3 <- value:
// 执行的代码
default:
// 所有通道都没有准备好,执行的代码
}
(1) 只能用于通道操作,要么是发送要么是接收
(2) 会监听所有通道,其中一个准备好就会执行相应的代码块。
(3) 多个通道都准备好,会随机选择一个通道执行。
(4) 所有通道都没有准备好,会执行 default 的代码。如果没有 default 子句,select 将阻塞,直到某个通道可以运行
4. for 语句:有 4 种形式
(1) for init; condition; post { } 和 C 语言的 for 一样
(2) for condition { } 和 C 的 while 一样
(3) for { } 无限循环
(4) For-each range 循环:可以对字符串、数组、切片等迭代输出元素,获得索引和值
strings := []string{"google", "runoob"}
for i, s := range strings {
fmt.Println(i, s)
}
如果是map的话,可以获得 key 和value
ap1 := make(map[int]float32)
map1[1] = 1.0
map1[2] = 2.0
for key, value := range map1 {
fmt.Printf("key is: %d - value is: %f\n", key, value)
}
三、结构体、切片
1. 声明结构体: type x struct
type Books struct {
title string
author string
}
2. 定义结构体: Books{"Go 语言", "www.runoob.com"}
3. 声明切片: var varname [] typename (切片是对数组的抽象)
4. 创建切片: var varname []typename= make([]typename, len)
5. 初始化切片:
(1) 直接赋值:s :=[] int {1,2,3 }
(2) 通过数组:s := arr[:]
(3) 通过数组的索引:s := arr[startIndex:endIndex];s := arr[:endIndex];arr[startIndex:]
(4) 通过切片初始化切片:s1 := s[startIndex:endIndex]
6. len() 计算切片的长度,cap() 计算切片的容量
7. 添加元素:numbers = append(numbers, 2,3,4)
8. 拷贝 source的内容到 target: copy(target, source)
四、map 集合
1. Map 是无序的键值对集合。可以迭代它,但它是无序的。
2. Map 是引用类型,将 Map 传递给函数或赋值给变量,都指向同一个数据结构。
3. 创建map: m := make(map[string]int, 10),创建一个初始容量为 10 的 Map
4. 使用字面量创建 Map:
m := map[string]int{
"apple": 1,
}
5. 遍历 Map:
for k, v := range m {
fmt.Printf("key=%s, value=%d\n", k, v)
}
6. 删除元素: delete(m, "banana")
五、类型转换
1. 整数转换为浮点(直接强转): var a int = 10;var b float64 = float64(a)
2. 字符串转换为整数Atoi:num, _ = strconv.Atoi(str)
3. 整数转换为字符串Itoa:str := strconv.Itoa(num)
4. 字符串转换为浮点数ParseFloat:fnum, err := strconv.ParseFloat(str, 64)
5. 浮点数转换为字符串FormatFloat:str := strconv.FormatFloat(num, 'f', 2, 64)。64位浮点数的格式进行转换,保留2位小数。
6. 类型断言:
var i interface{} = "Hello, World"
str, ok := i.(string)
使用类型断言将 i 转换为字符串,并赋值给str。ok表示转换是否成功。
接口类型也可以使用相同的方式
7. 字符串 转 字节数组: s := "abc"; arr := []byte(s)
8. 字节数组 转 字符串: 遍历数组,相加得字符串
六、接口
1. 接口把有共性的方法定义在一起,其他类型只要实现这些方法,就是实现了这个接口。从而实现了多态。
2. 代码实现:
type Phone interface { //定义接口Phone
call() //这个接口包含call方法
}
type NokiaPhone struct { //定义实现Phone接口的数据类型
}
func (nokiaPhone NokiaPhone) call() { //实现了call方法,就是实现了Phone接口
fmt.Println("I am Nokia, I can call you!")
}
func main() {
var phone Phone
phone = new(NokiaPhone)
phone.call()
}
七、错误处理
1. error 类型是接口类型,它的定义:
type error interface {
Error() string
}
2. errors.New 可返回一个错误对象: errors.New("square negative number")
八、并发
1. goroutine 是轻量级线程,调度方式由Golang 运行时管理,用户可以通过 通道和信号 来控制。
2. 通道:用于两个 goroutine 之间通过传递数据来同步运行。使用操作符 <
(1) 声明一个通道:ch := make(chan int)
(2) 发送数据到通道: ch <- v
(3) 通道接收数据:v := <-ch
3. 通道缓冲区:
(1) 声明带缓冲区的通道:ch := make(chan int, 100)
(2) 带缓冲区的通道,允许数据发送和接数据的goroutine 处于异步状态
(3) 缓冲区满了之后,goroutine会阻塞
4. range 遍历通道
go fibonacci(cap(c), c)
for i := range c {
fmt.Println(i)
}
(1) fibonacci 函数内部一边发送数据, for range 循环内部一边接收数据
(2) 接收速度比发送速度快的话,接收部分代码会阻塞。
(3) fibonacci 函数内部不 close通道的话,for range 循环会一直阻塞
九、数据库
1. mongodb:github.com/mongodb/mongo-go-driver
2. gorm:github.com/jinzhu/gorm