# Go 基础阶段
# 课前准备
# 安装 Go 语言
- 访问 go.dev (opens new window),点击 Download, 下载对应平台安装包, 安装即可
- 如果无法访问上述网址,可以改为访问 studygolang.com/dl (opens new window) 下载安装
- 如果访问 Github 速度比较慢, 建议配置 go mod proxy, 参考 goproxy.cn (opens new window) 里面的描述进行配置, 这样下载第三方依赖包的速度可以大大加快
# 配置 Go 语言开发环境
可以选择安装 VS Code (opens new window) , 或者 Goland (opens new window) ,对于 VS Code,需要安装 Go 插件 (opens new window)
# 下载课程示例代码
Windows 平台建议安装 git,其它系统自带,安装教程 (opens new window)
打开 go-by-example (opens new window), 克隆/下载课程示例项目
git clone https://github.com/wangkechun/go-by-example.git
- 进入课程示例项目代码目录,运行
go run example/01-hello/main.go
如果正确输出 hello world,则说明环境配置正确
# 参考资料
阅读: Go语言圣经(中文版) (opens new window)
案例课程: http://books.studygolang.com/gobyexample/
路线图: https://bytedance.feishu.cn/docs/doccn3SFTuFIAVr4CDZGx48KKdd
# Go 语言简介
# Go 语言有什么特点呢?
- 高性能 高并发
- 语法简单 跨平台
- 丰富的标准库
- 完善的工具链
- 静态链接 快速编译
- 垃圾回收
举个例子
简单几句代码, 就可以启动一个 web 服务
package main
import (
"fmt"
"net/http"
)
func main() {
http.Handle("/", http.FileServer(http.Dir(".")))
fmt.Println("启动web服务成功, 访问: http://localhost:8080")
http.ListenAndServe("localhost:8080", nil)
}
2
3
4
5
6
7
8
9
10
11
12
运行
go run web.go
由于 Go 入门很简单, 开发效率高, 性能比较好, 部署也简单, 所以让我们全面拥抱 GO 语言吧!
# 基础语法
# hello world
查看课程示例example/01-hello
目录的文件
先来看一下 go 语言中, hello word 的代码长啥样
// package main 代表这个文件属于 main 包的一部分
package main // main 包是用户程序的入口
// 导入其他包
import (
"fmt" // 标准库里面的 fmt 包, 主要用来输入输出字符串、格式化字符串的
)
// main 函数是执行的用户入口函数
func main() {
fmt.Println("hello world") // 调用了 fmt.Println 输出 hello word
}
2
3
4
5
6
7
8
9
10
11
12
把代码跑起来, 有两种方式:
直接运行
go run main.go
1编译后再运行
go build main.go ./main
1
2
# 变量
变量名由
字母、数字、下划线
组成, 其中首个字符不能为数字
# 变量类型
值类型
整型 浮点型 字符串 布尔型 结构体
引用类型
指针 切片 map 函数 接口 channel
# 变量声明
查看课程示例example/02-var
目录的文件
变量在使用前, 必须要先声明, 可以在声明时候手动赋值, 如果不赋值, 则默认是零值
显示声明, 使用 var 关键字
// 显式声明, 并手动指定类型, 但不赋值 var i int // 显式声明, 并手动指定类型, 手动赋值 var a string= "initial" // 多个变量在同一行同时声明 var b, c int = 1, 2
1
2
3
4
5
6
7
8类型推断
// 显式声明, 但是自动推导类型 var d = true var e float64
1
2
3
4省略 var 关键字, 并自动推导类型, 使用
:=
// 省略var, 自动推导类型, 并手动赋值 f := float32(e) // 只能在函数内部使用 g := a + "foo"
1
2
3
4
# 常量声明
使用 const
关键字
// 手动指定类型
const s string = "constant"
// 自动推导类型
const h = 500000000
const i = 3e20 / h
2
3
4
5
常量的值不可更改, 指的是该常量的内存空间存的内容不能修改
# 条件判断
Go 语言提供了以下几种条件判断语句:
语句 | 描述 |
---|---|
if 语句 | if 语句 由一个布尔表达式后紧跟一个或多个语句组成 |
switch 语句 | switch 语句用于基于不同条件执行不同动作 |
select 语句 | select 语句类似于 switch 语句。但是 select 会随机执行一个可运行的case, 如果没有 case 可运行,它将阻塞,直到有case可运行 |
注意: Go 没有三目运算符,所以不支持
?:
形式的条件判断
# if 语句
查看课程示例example/04-if
目录的文件
if
后面可以没有括号if
后面的开始大括号{
必须跟if
在同一行, 不能换行if
后面也可以定义变量,但只能出现一个分号if num := 9; num < 0 { // 在 if 后面定义变量 fmt.Println(num, "is negative") } else if num < 10 { fmt.Println(num, "has 1 digit") } else { fmt.Println(num, "has multiple digits") }
1
2
3
4
5
6
7
# switch 语句
查看课程示例example/05-switch
目录的文件
Go 的
switch
可以匹配任意类型switch
后面可以不加括号case
里也不需要加break
,默认情况下case
最后自带break
语句,匹配成功后就不会执行其他case
,如果需要执行后面的case
,可以使用fallthrough
关键字case
可以匹配多条件, 使用逗号分隔switch
后面可以不加匹配条件,然后在case
里再进行匹配t := time.Now() switch { case t.Hour() < 12: fmt.Println("It's before noon") default: fmt.Println("It's after noon") }
1
2
3
4
5
6
7
# 循环 for
在 Go 里面没有 while 循环、do while 循环,只有 for 循环
查看课程示例example/03-for
目录的文件
支持以下几种循环控制语句: (循环控制语句可以控制循环体内语句的执行过程)
控制语句 | 描述 |
---|---|
break 语句 | 用于中断跳出 当前 for 循环或跳出 switch 语句 |
continue 语句 | 用于跳过 当前循环的剩余语句,然后继续 进行下一轮循环 |
goto 语句 | 跳到 被标记的语句处 |
用 for
定义普通的循环, 条件是三段式的, 任何一段都可以省略. 在 for
循环里使用 continue
和 break
来跳出循环
// 普通for循环
for i := 0; i < 5; i++ {
fmt.Println(i)
}
// 使用continue
for i := 0; i < 5; i++ {
if i == 3 {
continue
}
fmt.Println(i)
}
// 使用break
for i := 0; i < 5; i++ {
if i == 3 {
break
}
fmt.Println(i)
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
用 for
定义 while
的功能
num := 1
for i <= 3 {
fmt.Println(i)
i = i + 1
}
2
3
4
5
用 for
定义死循环,相当于 while(true)
for { // 最简单的 for 循环, 条件都不写
fmt.Println("loop")
}
for true {
fmt.Println("loop")
}
2
3
4
5
6
# 数组 array
数组是具有相同类型的长度固定的一组数据序列, 其类型可以是原始类型或者自定义类型
查看课程示例example/06-array
目录的文件
package main
import "fmt"
func main() {
var a [5]int // 一维数组
a[4] = 100
fmt.Println("get:", a[2])
fmt.Println("len:", len(a))
b := [5]int{1, 2, 3, 4, 5} // 初始化
fmt.Println(b)
var twoD [2][3]int // 二维数组
for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ {
twoD[i][j] = i + j
}
}
fmt.Println("2d: ", twoD)
// 不能像 java 那样, 二维长度不同
// var twoE [2][]int 错误的
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
在真实业务代码里面, 我们很少直接使用数组, 因为它长度是固定的, 我们用的更多的是切片
# 切片 slice
切片与数组的区别: 切片的长度不是固定的而是可变的, 比数组的用途更加广泛
查看课程示例example/07-slice
目录的文件
切片
的声明
// 1. make 方式
// 2. 引用数组方式
// 3. 字面量初始化方式, 底层还是引用数组
2
3
https://www.yuque.com/vbaicai/po7hfk/xn277d#cqsZ7
切片
的本质
type slice struct {
array unsafe.Pointer
len int
cap int
}
2
3
4
5
https://www.yuque.com/vbaicai/po7hfk/xn277d#exZEu
可以通过 append
方法向切片中添加元素
// 需要一个变量或原变量来接收返回值, 因为切片可能会扩容
s = append(s, "d")
s = append(s, "e", "f")
// 因为slice底层, 实际上是存储了一个长度和一个容量,加一个指向数组的指针
// 在你执行append操作的时候,如果容量不够的话,会扩容并且返回新的slice
2
3
4
5
6
可以通过 copy
方法对切片进行复制,复制后是两个独立
的切片,更改元素相互不影响
c := make([]string, len(s))
copy(c, s)
fmt.Println(c) // [a b c d e f]
2
3
# 集合 map
map 是一种无序的键值对的集合, 也被称为映射、字典、 哈希
查看课程示例example/08-map
目录的文件
map
的声明
// 1. make 方式, 且可以同时对其进行初始化
// 2. 字面量初始化的方式, 底层是 make 方式
2
https://www.yuque.com/vbaicai/po7hfk/xn277d#vzDGO
map
的本质
https://www.yuque.com/vbaicai/po7hfk/xn277d#PPmWY
对 map
的访问, 通过”key下标“来访问的, 如果访问的key
不存在的话会返回0
注意: 对于不存在的key
返回0
,如果一个key
的值也为0
,就很容易产生不必要的误会,因此Go
在查询key
时返回了两个值,一个是结果,另一个是bool
类型的值代表是否存在
r, ok := m["unknow"]
fmt.Println(r, ok) // 0 false
2
可以使用 delete
函数来删除 map
中的元素
delete(m, "one")
# 遍历 range
数组、切片、
map
等都可以使用range
来遍历
查看课程示例example/09-range
目录的文件
通过range
可以得到索引和值
package main
import "fmt"
func main() {
nums := []int{2, 3, 4}
sum := 0
for i, num := range nums {
sum += num
if num == 2 {
fmt.Println("index:", i, "num:", num) // index: 0 num: 2
}
}
fmt.Println(sum) // 9
m := map[string]string{"a": "A", "b": "B"}
for k, v := range m {
fmt.Println(k, v) // b 8; a A
}
// 可以只要一个值
for k := range m {
fmt.Println("key", k) // key a; key b
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 函数 func
查看课程示例example/10-func
目录的文件
# 指针 point
查看课程示例example/10-func
目录的文件
# 结构体 struct
查看课程示例example/10-func
目录的文件
# 错误处理
查看课程示例example/10-func
目录的文件
# 标准库
Go 工程进阶 →