开始

Go(又称 Golang)是谷歌 2007 年设计、2009 年开源的静态强类型、编译型、原生并发编程语言,主打简洁、高效、原生高并发,专为解决 C++ 编译缓慢、并发编程复杂、项目依赖管理混乱等开发痛点而生。

应用场景: 后端高并发服务、区块链开发、云原生底层工具。

语言/框架 RPS(每秒请求数) 内存占用 延迟
Go (Gin) 105,000 190 MB 10 ms
Java (Spring) 40,000 1.4 GB 50 ms
Python (FastAPI) 8,000 1.2 GB 150 ms
同样的 Web 服务,Go 的处理能力是 Java 的 2.6 倍、Python 的 13 倍,内存只用了 Java 的 1/7、Python 的 1/6,延迟也最低。
1
2
3
4
5
6
7
8
9
10
# 开发时快速测试代码
go run start.go

# 先编译生成.exe文件 (构建生产版本)
go build start.go
./start.exe

go fmt # 统一代码风格

go test # 进行单元测试

开始的模板:

1
2
3
4
5
6
package main
import "fmt"

func main() {
    fmt.Println("Hello,go!")
}

💡Go语言使用大括号定义代码块,左大括号必须与函数声明在同一行,这是Go的强制代码风格。

输入输出:

1
2
3
4
5
6
7
8
9
10
11
12
var name string 
var age int
// 输入
fmt.Scan(&name, &age)

// 输出
fmt.Print("Hello") // 不换行
fmt.Println("Hello") // 自动换行(最常用)
fmt.Printf("我%d岁\n", 18) // 格式化输出,像C语言

// 常用格式化符号: %d 整数,%s 字符串,%f 小数,%t true/false
// %.2f 保留2位小数

基本语法

变量与常量

声明变量
方式 1:完整声明

1
2
// var 变量名 类型 = 值
var a int = 10

方式 2:类型推导

1
2
// var 变量名 = 值
var b = 20 // 编译器会根据初始值自动推断类型,这里是int

方式 3:简短声明

1
2
// 变量名 := 值
c := 30

编译器自动推导类型,代码最简洁。但只能在函数内部使用,包级变量必须用 var 声明。。
:= 左侧必须是至少一个新变量,不能全是已声明变量(比如 a, b := 10, 20 中,只要有一个新变量就可以)。

多变量声明

1
2
var x, y, z int = 1, 2, 3 // 同类型多变量
name, age := "Alice", 25 // 不同类型多变量(类型推导)

Go 会分别推导两个变量的类型(namestringageint),是函数内多变量声明的常用方式。

常量声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// const 常量名 = 值
const Pi = 3.14159
const MaxSize = 100

// 支持批量声明
const (
Monday = 1
Tuesday = 2
Wednesday = 3
)

//支持 iota 枚举
const (
_ = iota // iota 初始为0,这里用_跳过
A
B
C
) // A=1, B=2, C=3,自动递增,适合定义状态码、枚举值

变量零值
Go 中声明但未赋值的变量会被赋予零值

  • int/float0/0.0
  • boolfalse
  • string""
  • 指针 / 切片 / 映射:nil

💡Go 强制要求声明的变量必须被使用,否则编译报错。

基本数据类型

整数类型

类型 占用空间 取值范围
int8 1 字节 -128 ~ 127
int16 2 字节 -32768 ~ 32767
int32 4 字节 约 ±21 亿
int64 8 字节 约 ±922 京
int 平台相关 32/64 位(32 位系统是int32,64 位系统是int64

日常开发优先用 int,不用自己纠结位数,编译器会适配平台。

浮点数类型

类型 占用空间 精度
float32 4 字节 约 6-7 位小数
float64 8 字节 约 15 位小数

默认用 float64,精度更高,避免计算误差。

布尔类型
只有两个取值:true(真)/false(假)。

💡不能用 0/1 代替 false/true,Go 是强类型语言。

字符串类型
双引号包裹,是不可变类型,一旦创建就不能修改单个字符。
Go 里定义多行字符串,必须用反引号包裹,而不是双引号 "

用双引号写字符串时,\n\t\" 这类转义字符会被解析(比如 \n 会变成换行);但用反引号时,所有转义字符都会被当作普通文本保留,不会解析。

也不是没办法修改字符串:先把字符串转换成修改的 rune 切片,修改完成后再转回字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main
import "fmt"

func main() {
str := "Hello"

// 1. 转换为 rune 切片(支持中文/Unicode)
runes := []rune(str) // str复制一份,放到一个新的地方(runes), 不是把原来的字符串拿过来改!
// 2. 修改切片中的字符
runes[0] = 'h'
// 3. 再转回字符串
newStr := string(runes)
fmt.Println(newStr) // 输出:hello
}

len(str) 获得字符串的长度(按字节算)
len(runes) 获得rune的字符长度(按字符个数算)

类型转换

Go 是强类型语言:不同类型不能直接运算,必须手动转。
不同类型不能运算

strconv 包

匿名变量

匿名变量:用下划线 _ 代替变量名,用来 “扔掉” 不需要的值

  • 不用写变量名
  • 不占用内存
  • 不会报 “变量未使用” 错误

什么时候用??
1)函数返回多个值,只要一个,扔掉其他
Go 很多函数返回 (结果,错误)
只要结果、不想管错误,就用_扔掉错误。
2)多变量赋值,只想要几个、剩下扔掉
3)循环 / 遍历,只要值、不要索引

语句

switch语句
默认自带 break,匹配一个就结束

1
2
3
4
5
6
7
day := 3
switch day {
case 1: fmt.Println("周一")
case 2: fmt.Println("周二")
case 3: fmt.Println("周三")
default: fmt.Println("其他")
}

fallthrough:继续往下执行

1
2
3
4
5
6
7
8
9
10
switch 2 {
case 2:
fmt.Println("2")
fallthrough // 穿透到下一个case
default:
fmt.Println("default")
}
// 输出:
// 2
// default

循环语句
Go 只有 for,没有 while/do-while

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 标准for
for i := 1; i <= 10; i++ {
fmt.Println(i)
}
// 三种简写方式
// 1. 只有条件
i := 0
for i < 5 {
fmt.Println(i)
i++
}
// 2. 无限循环
for{
fmt.Println("无限循环")
}
// 3. 省略更新
i := 0
for ; i < 5; {
fmt.Println(i)
i++
}

break跳出当前一层循环,而 break + label 则是跳出多层

1
2
3
4
5
6
7
8
9
10
Outer:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if j == 1 {
break Outer // 直接跳出两层
}
fmt.Println(i, j)
}
}
// 只输出:0 0

continue跳过本次,进入下一轮, continue + label 则跳到外层循环

1
2
3
4
5
6
7
8
9
10
11
12
13
Outer:
for i := 1; i <= 3; i++ {
for j := 1; j <= 3; j++ {
if j == 2 {
continue Outer // 直接跳到外层下一次
}
fmt.Println(i, j)
}
}
// 输出:
// 1 1
// 2 1
// 3 1

for-range 遍历数组 / 切片 / 字符串
语法模板:

1
2
3
for 索引, 值 := range 数据 { 
...
}

示例:

1
2
3
4
5
6
7
8
ages := []int{5, 8, 7}
for i, v := range ages {
fmt.Println(i, v)
}
// 输出:
// 0 5
// 1 8
// 2 7