Go 语言零基础入门教程 — 云原生时代的系统编程语言

适用人群:有其他语言基础的开发者、后端开发者、云原生开发者
学习时长:约3-5天(每天4小时)
Go版本:1.22+
适用场景:微服务、云原生、高并发后端、CLI工具、区块链

一、Go 是什么?

Go(Golang)是Google开发的编程语言,以简洁、高效、并发性能著称,是云原生时代的首选语言。

特点说明
上手难度★★☆☆☆(语法简洁,但需要理解并发模型)
核心优势编译型、高并发、部署简单、标准库强大
主要用途微服务、K8S/Docker、高并发后端、DevOps工具
薪资水平初级15-25K,中级25-40K,高级40K+
代表项目Docker、Kubernetes、Etcd、Prometheus

二、环境搭建

# macOS
brew install go

# Ubuntu
sudo apt update
sudo apt install golang-go

# Windows
# 下载:https://go.dev/dl/

# 验证安装
go version

# 配置环境变量(~/.bashrc 或 ~/.zshrc)
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
export GOPROXY=https://goproxy.cn,direct  # 国内代理


三、Hello World

// main.go
package main

import "fmt"

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

# 运行
go run main.go

# 编译
go build -o myapp main.go
./myapp


四、Go 基础语法

4.1 变量与类型

package main

import "fmt"

func main() {
    // ====================
    // 变量声明
    // ====================
    
    // 方式1:完整声明
    var name string = "张三"
    var age int = 25
    
    // 方式2:类型推断
    var height = 175.5
    
    // 方式3:短变量声明(最常用)
    city := "北京"
    isActive := true
    
    // 方式4:多变量声明
    var (
        username = "admin"
        email    = "admin@example.com"
        role     = "管理员"
    )
    
    // 常量
    const Pi = 3.14159
    const (
        StatusOK = 200
        StatusNotFound = 404
    )
    
    fmt.Println(name, age, height, city, isActive)
    fmt.Println(username, email, role)

    // ====================
    // 基本类型
    // ====================
    // 整数:int, int8, int16, int32, int64
    // 无符号整数:uint, uint8, uint16, uint32, uint64
    // 浮点数:float32, float64
    // 布尔:bool
    // 字符串:string
    // 字节:byte (uint8别名)
    // rune:int32别名,表示Unicode码点

    // ====================
    // 零值
    // ====================
    // 数字类型:0
    // 布尔类型:false
    // 字符串:""
    // 指针、切片、映射、函数、接口、通道:nil
}

4.2 数组与切片

package main

import "fmt"

func main() {
    // ====================
    // 数组(固定长度)
    // ====================
    var arr [5]int = [5]int{1, 2, 3, 4, 5}
    arr2 := [...]int{1, 2, 3}  // 自动推断长度
    
    fmt.Println(arr, arr2)
    
    // ====================
    // 切片(动态数组,最常用)
    // ====================
    // 创建切片
    nums := []int{1, 2, 3, 4, 5}
    nums2 := make([]int, 5)      // 长度5
    nums3 := make([]int, 0, 10)  // 长度0,容量10
    
    // 增
    nums = append(nums, 6)
    nums = append(nums, 7, 8, 9)
    
    // 切片操作
    sub := nums[1:4]    // [2, 3, 4]
    first3 := nums[:3]  // [1, 2, 3]
    last3 := nums[6:]   // [7, 8, 9]
    
    // 长度和容量
    fmt.Println(len(nums), cap(nums))
    
    // 遍历
    for i, v := range nums {
        fmt.Printf("索引: %d, 值: %d\n", i, v)
    }
    
    // ====================
    // 切片是引用类型
    // ====================
    original := []int{1, 2, 3, 4, 5}
    copied := make([]int, len(original))
    copy(copied, original)  // 深拷贝
    
    _ = nums2
    _ = nums3
    _ = sub
    _ = first3
    _ = last3
}

4.3 Map(字典)

package main

import "fmt"

func main() {
    // 创建map
    user := map[string]interface{}{
        "name": "张三",
        "age":  25,
        "city": "北京",
    }
    
    // 或使用make
    scores := make(map[string]int)
    scores["数学"] = 95
    scores["英语"] = 88
    scores["编程"] = 92
    
    // 增/改
    user["email"] = "zhangsan@example.com"
    
    // 查
    name := user["name"]
    score, exists := scores["数学"]  // 两个返回值
    if exists {
        fmt.Println("数学成绩:", score)
    }
    
    // 删
    delete(scores, "英语")
    
    // 遍历
    for key, value := range user {
        fmt.Printf("%s: %v\n", key, value)
    }
    
    // 判断key是否存在
    if _, ok := user["phone"]; !ok {
        fmt.Println("没有手机号")
    }
    
    fmt.Println(name)
}

4.4 条件与循环

package main

import "fmt"

func main() {
    // ====================
    // 条件判断
    // ====================
    age := 25
    
    if age >= 18 {
        fmt.Println("成年人")
    } else if age >= 12 {
        fmt.Println("青少年")
    } else {
        fmt.Println("儿童")
    }
    
    // if 可以包含初始化语句
    if score := 85; score >= 90 {
        fmt.Println("优秀")
    } else if score >= 60 {
        fmt.Println("及格")
    }
    
    // switch(不需要break)
    day := "Monday"
    switch day {
    case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday":
        fmt.Println("工作日")
    case "Saturday", "Sunday":
        fmt.Println("周末")
    default:
        fmt.Println("未知")
    }
    
    // ====================
    // 循环(只有for)
    // ====================
    
    // 基本for
    for i := 0; i < 5; i++ {
        fmt.Println(i)
    }
    
    // while风格
    count := 0
    for count < 5 {
        fmt.Println(count)
        count++
    }
    
    // 无限循环
    // for {
    //     // break退出
    // }
    
    // range遍历
    fruits := []string{"苹果", "香蕉", "橙子"}
    for i, fruit := range fruits {
        fmt.Printf("%d: %s\n", i, fruit)
    }
    
    // 只要值,不要索引
    for _, fruit := range fruits {
        fmt.Println(fruit)
    }
    
    // 遍历map
    user := map[string]string{"name": "张三", "city": "北京"}
    for key, value := range user {
        fmt.Printf("%s: %s\n", key, value)
    }
}


五、函数

package main

import (
    "errors"
    "fmt"
)

// ====================
// 基本函数
// ====================
func greet(name string) string {
    return fmt.Sprintf("你好,%s!", name)
}

// ====================
// 多返回值
// ====================
func divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, errors.New("除数不能为零")
    }
    return a / b, nil
}

// ====================
// 命名返回值
// ====================
func getUser(id int) (name string, age int, err error) {
    // 命名返回值可以直接使用
    name = "张三"
    age = 25
    return  // 裸返回
}

// ====================
// 可变参数
// ====================
func sum(numbers ...int) int {
    total := 0
    for _, n := range numbers {
        total += n
    }
    return total
}

// ====================
// 函数作为参数
// ====================
func apply(f func(int, int) int, a, b int) int {
    return f(a, b)
}

// ====================
// 匿名函数(闭包)
// ====================
func makeCounter() func() int {
    count := 0
    return func() int {
        count++
        return count
    }
}

func main() {
    fmt.Println(greet("张三"))
    
    result, err := divide(10, 3)
    if err != nil {
        fmt.Println("错误:", err)
    } else {
        fmt.Println("结果:", result)
    }
    
    fmt.Println(sum(1, 2, 3, 4, 5))
    
    add := func(a, b int) int { return a + b }
    fmt.Println(apply(add, 3, 4))
    
    counter := makeCounter()
    fmt.Println(counter())  // 1
    fmt.Println(counter())  // 2
    fmt.Println(counter())  // 3
}


六、结构体(类的替代)

package main

import "fmt"

// ====================
// 定义结构体
// ====================
type User struct {
    ID       int
    Name     string
    Email    string
    Age      int
    IsActive bool
}

// 方法(值接收者)
func (u User) Greet() string {
    return fmt.Sprintf("我是%s,今年%d岁", u.Name, u.Age)
}

// 方法(指针接收者 - 可以修改结构体)
func (u *User) SetName(name string) {
    u.Name = name
}

// 构造函数(Go惯例)
func NewUser(name string, email string, age int) *User {
    return &User{
        Name:     name,
        Email:    email,
        Age:      age,
        IsActive: true,
    }
}

// ====================
// 接口
// ====================
type Logger interface {
    Log(message string)
    GetLog() string
}

func (u User) Log(message string) {
    fmt.Printf("[%s] %s\n", u.Name, message)
}

func (u User) GetLog() string {
    return fmt.Sprintf("User: %s", u.Name)
}

// 接口作为参数
func ProcessLog(l Logger) {
    l.Log("处理中...")
    fmt.Println(l.GetLog())
}

// ====================
// 继承(组合)
// ====================
type Admin struct {
    User        // 嵌入User(匿名字段)
    Role string
}

func (a Admin) Greet() string {
    return fmt.Sprintf("%s(%s)", a.User.Greet(), a.Role)
}

func main() {
    // 创建实例
    user := NewUser("张三", "zhangsan@example.com", 25)
    fmt.Println(user.Greet())
    
    user.SetName("李四")
    fmt.Println(user.Greet())
    
    // 接口使用
    ProcessLog(*user)
    
    // 组合
    admin := Admin{
        User: User{Name: "管理员", Age: 30},
        Role: "superadmin",
    }
    fmt.Println(admin.Greet())
    fmt.Println(admin.User.Greet())  // 也可以访问嵌入的方法
}


七、并发编程(Go的核心优势)

package main

import (
    "fmt"
    "sync"
    "time"
)

// ====================
// Goroutine(轻量级线程)
// ====================
func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done()  // 完成时通知WaitGroup
    
    fmt.Printf("Worker %d 开始\n", id)
    time.Sleep(time.Second)  // 模拟工作
    fmt.Printf("Worker %d 完成\n", id)
}

func mainGoroutine() {
    var wg sync.WaitGroup
    
    // 启动5个goroutine
    for i := 1; i <= 5; i++ {
        wg.Add(1)
        go worker(i, &wg)  // go关键字启动goroutine
    }
    
    wg.Wait()  // 等待所有goroutine完成
    fmt.Println("所有worker完成")
}

// ====================
// Channel(通道 - goroutine间通信)
// ====================
func mainChannel() {
    // 创建channel
    ch := make(chan string)
    
    // 发送数据到channel
    go func() {
        time.Sleep(time.Second)
        ch <- "Hello from goroutine"
    }()
    
    // 从channel接收数据
    msg := <-ch
    fmt.Println(msg)
    
    // 带缓冲的channel
    buffered := make(chan int, 3)
    buffered <- 1
    buffered <- 2
    buffered <- 3
    // buffered <- 4  // 会阻塞,因为缓冲区已满
    
    fmt.Println(<-buffered, <-buffered, <-buffered)
}

// ====================
// 生产者-消费者模式
// ====================
func producer(ch chan<- int) {
    for i := 0; i < 10; i++ {
        ch <- i
        fmt.Printf("生产: %d\n", i)
    }
    close(ch)  // 关闭channel
}

func consumer(ch <-chan int, id int) {
    for num := range ch {
        fmt.Printf("消费者%d 消费: %d\n", id, num)
        time.Sleep(100 * time.Millisecond)
    }
}

func mainProducerConsumer() {
    ch := make(chan int, 5)
    
    // 启动1个生产者
    go producer(ch)
    
    // 启动3个消费者
    var wg sync.WaitGroup
    for i := 1; i <= 3; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            consumer(ch, id)
        }(i)
    }
    
    wg.Wait()
    fmt.Println("所有消费者完成")
}

// ====================
// Select(多路复用)
// ====================
func mainSelect() {
    ch1 := make(chan string)
    ch2 := make(chan string)
    
    go func() {
        time.Sleep(1 * time.Second)
        ch1 <- "来自channel1"
    }()
    
    go func() {
        time.Sleep(2 * time.Second)
        ch2 <- "来自channel2"
    }()
    
    // 等待第一个完成的
    select {
    case msg := <-ch1:
        fmt.Println(msg)
    case msg := <-ch2:
        fmt.Println(msg)
    case <-time.After(3 * time.Second):
        fmt.Println("超时")
    }
}


八、错误处理

package main

import (
    "errors"
    "fmt"
)

// 自定义错误
var (
    ErrNotFound = errors.New("记录不存在")
    ErrInvalid  = errors.New("参数无效")
)

// 带上下文的错误
type ValidationError struct {
    Field   string
    Message string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("验证错误 [%s]: %s", e.Field, e.Message)
}

// 错误处理模式
func findUser(id int) (string, error) {
    if id <= 0 {
        return "", &ValidationError{Field: "id", Message: "必须大于0"}
    }
    if id > 100 {
        return "", ErrNotFound
    }
    return "张三", nil
}

func main() {
    name, err := findUser(0)
    if err != nil {
        // 使用errors.Is判断特定错误
        if errors.Is(err, ErrNotFound) {
            fmt.Println("用户不存在")
        }
        
        // 使用errors.As获取具体错误类型
        var validationErr *ValidationError
        if errors.As(err, &validationErr) {
            fmt.Printf("字段: %s, 消息: %s\n", validationErr.Field, validationErr.Message)
        }
        
        fmt.Println("错误:", err)
        return
    }
    
    fmt.Println("找到用户:", name)
}


九、JSON 处理

package main

import (
    "encoding/json"
    "fmt"
)

// 结构体标签
type User struct {
    ID       int    `json:"id"`
    Name     string `json:"name"`
    Email    string `json:"email,omitempty"`  // 空值时省略
    Password string `json:"-"`                // 永不序列化
    Age      int    `json:"age"`
}

func main() {
    // 序列化
    user := User{ID: 1, Name: "张三", Email: "test@example.com", Password: "secret", Age: 25}
    jsonBytes, err := json.Marshal(user)
    if err != nil {
        fmt.Println("序列化错误:", err)
        return
    }
    fmt.Println(string(jsonBytes))
    // {"id":1,"name":"张三","email":"test@example.com","age":25}
    
    // 格式化输出
    jsonBytes, _ = json.MarshalIndent(user, "", "  ")
    fmt.Println(string(jsonBytes))
    
    // 反序列化
    jsonStr := `{"id":2,"name":"李四","email":"lisi@example.com","age":30}`
    var user2 User
    err = json.Unmarshal([]byte(jsonStr), &user2)
    if err != nil {
        fmt.Println("反序列化错误:", err)
        return
    }
    fmt.Printf("%+v\n", user2)
    
    // 动态JSON(不确定结构)
    var data map[string]interface{}
    json.Unmarshal([]byte(jsonStr), &data)
    fmt.Println(data["name"])
}


十、HTTP 服务(Gin框架)

# 安装Gin
go get -u github.com/gin-gonic/gin

// main.go
package main

import (
    "net/http"
    "strconv"
    
    "github.com/gin-gonic/gin"
)

// 模型
type User struct {
    ID    int    `json:"id"`
    Name  string `json:"name" binding:"required"`
    Email string `json:"email" binding:"required,email"`
    Age   int    `json:"age" binding:"min=0,max=150"`
}

// 模拟数据库
var users = []User{
    {ID: 1, Name: "张三", Email: "zhangsan@example.com", Age: 25},
    {ID: 2, Name: "李四", Email: "lisi@example.com", Age: 30},
}
var nextID = 3

func main() {
    r := gin.Default()
    
    // 路由组
    api := r.Group("/api")
    {
        // GET - 用户列表
        api.GET("/users", func(c *gin.Context) {
            c.JSON(http.StatusOK, gin.H{"data": users})
        })
        
        // GET - 单个用户
        api.GET("/users/:id", func(c *gin.Context) {
            id, _ := strconv.Atoi(c.Param("id"))
            for _, u := range users {
                if u.ID == id {
                    c.JSON(http.StatusOK, gin.H{"data": u})
                    return
                }
            }
            c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"})
        })
        
        // POST - 创建用户
        api.POST("/users", func(c *gin.Context) {
            var newUser User
            if err := c.ShouldBindJSON(&newUser); err != nil {
                c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
                return
            }
            
            newUser.ID = nextID
            nextID++
            users = append(users, newUser)
            
            c.JSON(http.StatusCreated, gin.H{"data": newUser})
        })
        
        // PUT - 更新用户
        api.PUT("/users/:id", func(c *gin.Context) {
            id, _ := strconv.Atoi(c.Param("id"))
            var updated User
            if err := c.ShouldBindJSON(&updated); err != nil {
                c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
                return
            }
            
            for i, u := range users {
                if u.ID == id {
                    updated.ID = id
                    users[i] = updated
                    c.JSON(http.StatusOK, gin.H{"data": updated})
                    return
                }
            }
            c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"})
        })
        
        // DELETE - 删除用户
        api.DELETE("/users/:id", func(c *gin.Context) {
            id, _ := strconv.Atoi(c.Param("id"))
            for i, u := range users {
                if u.ID == id {
                    users = append(users[:i], users[i+1:]...)
                    c.JSON(http.StatusOK, gin.H{"message": "删除成功"})
                    return
                }
            }
            c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"})
        })
    }
    
    r.Run(":8080")
}


学习建议

  1. 先理解Go的设计哲学:少即是多,显式优于隐式
  2. 重点掌握切片和map,这是最常用的数据结构
  3. 深入理解goroutine和channel,这是Go的核心竞争力
  4. 养成错误处理的习惯,Go的错误处理是显式的
  5. 学习Gin框架,做后端API开发的首选

下一步学习

返回首页