golang 简明语法教程
Go语言(Golang)简明语法教程
1. Hello World & 模块
// 初始化模块: go mod init example.com/m
// 运行: go run main.go
// 编译: go build main.go
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}2. 基本数据类型
bool
string // 只读的字节切片
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // uint8 的别名
rune // int32 的别名,表示一个 Unicode 码点
float32 float64
complex64 complex1283. 变量声明
// 标准声明
var a int = 10
var b = 10 // 类型推导
c := 10 // 短变量声明,仅函数内可用
```go
// 批量声明
var (
name string = "Ada"
age int = 4
isAI bool = true
)变量遮蔽问题
Go允许内层变量遮蔽外层变量,这是常见陷阱。
x := 1
{
x := 2 // 遮蔽外层 x
fmt.Println(x) // 输出 2
}
fmt.Println(x) // 输出 1,外层不变4. 常量
const PI = 3.14
const (
Monday = iota // 0
Tuesday // 1
Wednesday // 2
)5. 流程控制
if
if x := 10; x > 5 { // 支持初始化语句
fmt.Println("x 大于 5")
} else {
fmt.Println("x 不大于 5")
}for(Go 只有 for 一种循环)
// 1. 经典 for(三个语句:初始化; 条件; 后置)
for i := 0; i < 5; i++ {
fmt.Println(i)
}
// 2. 类似 while(只有条件)
sum := 0
for sum < 100 {
sum += 10
}
// 3. 无限循环(没有条件)
for {
// break 或 return 退出
}
// 4. range 遍历数组/切片
nums := []int{1, 2, 3}
for i, v := range nums { // 索引和值
fmt.Println(i, v)
}
for i := range nums { // 只获取索引
fmt.Println(i)
}
for _, v := range nums { // 只获取值(用 _ 忽略索引)
fmt.Println(v)
}
for range nums { // 只迭代,不获取任何值(用于需要执行固定次数的场景)
fmt.Println("iteration")
}
// 5. range 遍历 map
m := map[string]int{"a": 1, "b": 2}
for k, v := range m { // 键和值
fmt.Println(k, v)
}
for k := range m { // 只获取键
fmt.Println(k)
}
// 6. range 遍历字符串(遍历 rune)
s := "你好"
for i, r := range s { // 字节索引和 rune 值
fmt.Printf("%d: %c\n", i, r)
}
// 7. range 遍历 channel
ch := make(chan int, 3)
ch <- 1; ch <- 2; ch <- 3
close(ch)
for v := range ch { // 遍历直到 channel 关闭
fmt.Println(v)
}
// 8. break 和 continue
for i := 0; i < 10; i++ {
if i == 3 {
continue // 跳过本次迭代
}
if i == 7 {
break // 退出循环
}
fmt.Println(i)
}
// 9. label 配合 break/continue(跳出多层循环)
outer:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if i == 1 && j == 1 {
break outer // 跳出外层循环
}
fmt.Println(i, j)
}
}
// 10. for 初始化语句(支持短变量声明)
for i, j := 0, 10; i < j; i, j = i+1, j-1 {
fmt.Println(i, j)
}switch
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("macOS")
case "linux":
fmt.Println("Linux")
default:
fmt.Println("Other")
}
// switch 无需 break,自动中断
// fallthrough 可继续执行下一个 case6. 数组和切片(Slice)
// 数组(固定长度)
var arr [5]int
arr2 := [3]string{"a", "b", "c"}
// 切片(动态数组)
slice := []int{1, 2, 3}
slice = append(slice, 4)
// make 创建指定长度和容量
s := make([]int, 5, 10) // len=5, cap=10
// 切片操作
sub := slice[1:4] // 从索引1到3slices 包(Go 1.21+)
import "slices"
// 查找元素
index := slices.Index(slice, 2) // 返回索引,不存在返回-1
contains := slices.Contains(slice, 2) // 返回bool
// 排序
slices.Sort(slice) // 升序
slices.SortFunc(slice, func(a, b int) int { return b - a }) // 自定义排序
// 反转
slices.Reverse(slice)
// 去重(需要先排序)
unique := slices.Compact(slice)
// 比较
equal := slices.Equal(slice, []int{1, 2, 3})
// 复制
copySlice := slices.Clone(slice)
// 删除元素
slice = slices.Delete(slice, 1, 3) // 删除索引1到3的元素
// 插入元素
slice = slices.Insert(slice, 1, 10, 20) // 在索引1处插入10和207. Map(字典)
m := make(map[string]int)
m["age"] = 18
m2 := map[string]string{"name": "Ada"}
// 检查键是否存在
value, ok := m["age"] // ok 为 bool
// 删除
delete(m, "age")maps 包(Go 1.21+)
import "maps"
// 复制
copyMap := maps.Clone(m)
// 比较
equal := maps.Equal(m, map[string]int{"age": 18})
// 清空
maps.Clear(m)
// 合并(覆盖)
maps.Copy(m, map[string]int{"age": 20, "height": 180})
// 获取所有键
keys := maps.Keys(m)
// 获取所有值
values := maps.Values(m)8. 函数
// 普通函数
func add(a, b int) int {
return a + b
}
// 多返回值
func div(a, b int) (int, int) {
return a/b, a%b
}
// 命名返回值
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return // 裸返回
}
// 可变参数
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
```go
// defer:延迟执行,常用于资源释放。在函数返回前按 LIFO 顺序执行。
func doSomething() {
f, _ := os.Open("file.txt")
defer f.Close()
}
// 闭包用法:函数捕获外部变量,形成闭包
func counter() func() int {
count := 0 // 被内层函数捕获
return func() int {
count++
return count
}
}闭包注意事项
在goroutine中使用循环变量时需注意:
nums := []int{1, 2, 3}
for _, n := range nums {
go func(x int) { // 传参避免问题
fmt.Println(x)
}(n)
}9. 指针
var p *int
i := 42
p = &i // 取地址
fmt.Println(*p) // 解引用
// new 函数分配内存
p2 := new(int)基于地址的用法(指针高级)
指针常用于函数修改调用者变量,或传递大结构体避免拷贝开销。
// 函数通过指针修改外部变量
func increment(p *int) {
*p++
}
x := 10
increment(&x)
fmt.Println(x) // 11
// 大结构体用指针接收者
type BigStruct struct {
data [1000]int
}
func (b *BigStruct) process() {
b.data[0] = 99
}
bs := BigStruct{}
bs.process() // 自动取地址
fmt.Println(bs.data[0]) // 99引用类型无需指针:切片、map、channel、函数、接口是引用,修改自动生效。
10. 类型定义 (Type)
// 1. 类型定义 (Type Definition) - 创建新类型
type MyInt int
// 2. 类型别名 (Type Alias) - 仅起别名,类型相同
type MyAlias = int
// 3. 定义函数类型
type Handler func(int) bool11. 结构体 (Struct)
type Person struct {
Name string `json:"name"` // 结构体标签 (Tag)
Age int `json:"age"`
}
// 匿名结构体
point := struct {
X, Y int
}{10, 20}方法 (Methods)
func (p Person) SayHello() { // 值接收者
fmt.Printf("Hello, I'm %s\n", p.Name)
}
func (p *Person) Birthday() { // 指针接收者,可修改
p.Age++
}“继承” (组合/嵌套)
Go 语言没有类继承,通过结构体嵌套(Embedding)实现组合。
type Admin struct {
Person // 匿名嵌套
Level int
}
a := Admin{
Person: Person{Name: "Linus", Age: 50},
Level: 1,
}
fmt.Println(a.Name) // 直接访问嵌套字段
a.SayHello() // 直接调用嵌套方法12. 接口
type Speaker interface {
Speak() string
}
func Greet(s Speaker) {
fmt.Println(s.Speak())
}
// any:空接口 interface{} 的别名,可代表任何类型
var x any = "hello"
// 类型断言
s, ok := x.(string)
// 类型 Switch
switch v := x.(type) {
case int:
fmt.Println("int", v)
case string:
fmt.Println("string", v)
}13. 错误处理
func sqrt(x float64) (float64, error) {
if x < 0 {
return 0, errors.New("负数无平方根")
}
return math.Sqrt(x), nil
}
// 使用
result, err := sqrt(-1)
if err != nil {
fmt.Println(err)
}14. 并发:Goroutine 和 Channel
// 启动 goroutine
go func() {
fmt.Println("我在 goroutine 中")
}()
// Channel
ch := make(chan int)
go func() {
ch <- 42 // 发送
}()
value := <-ch // 接收
// 带缓冲 channel
ch2 := make(chan string, 2)
ch2 <- "hello"
ch2 <- "world"
// select 多路复用
select {
case msg := <-ch:
fmt.Println(msg)
case <-time.After(1 * time.Second):
fmt.Println("超时")
}15. 泛型 (Generics)
// 泛型函数
func MapKeys[K comparable, V any](m map[K]V) []K {
r := make([]K, 0, len(m))
for k := range m {
r = append(r, k)
}
return r
}
// 泛型结构体
type Stack[T any] struct {
elements []T
}16. init 函数
func init() {
// 包加载时自动执行,早于 main 函数
// 常用于初始化配置、注册驱动等
}17. 单元测试
// 文件名必须以 _test.go 结尾
// 函数名必须以 Test 开头
func TestAdd(t *testing.T) {
got := Add(1, 2)
if got != 3 {
t.Errorf("Add(1, 2) = %d; want 3", got)
}
}18. 常用标准库
fmt:格式化输入输出time:时间处理os/os/exec:系统操作net/http:构建 Web 服务encoding/json:JSON 序列化


