go基础语法

Go学习

本文由ai生成

文章目录

1. 环境搭建

1.1 下载安装

# 访问官网下载:https://go.dev/dl/
# 安装后验证
go version

1.2 配置编辑器

  • 安装 VS Code
  • 安装 Go 插件(在扩展中搜索 “Go”)
  • VS Code 会自动提示安装所需工具,点击 “Install All”

1.3 第一个程序

// hello.go
package main

import "fmt"

func main() {
    fmt.Println("Hello, World!")
}
# 运行方式1:直接运行
go run hello.go

# 运行方式2:编译后运行
go build hello.go
./hello

2. 基础语法

2.1 变量声明

package main

import "fmt"

func main() {
    // 方式1:自动推断类型(最常用)
    a := 1
    
    // 方式2:var + 自动推断
    var b = 2
    
    // 方式3:先声明后赋值(必须指定类型)
    var c int
    c = 3
    
    // 方式4:一次声明多个
    var x, y, z int = 1, 2, 3
    m, n := 10, 20
    
    // 注意:变量声明后必须使用,否则编译报错
    // 可以用 _ 忽略不用的变量
    _, value := 100, 200
    
    fmt.Println(a, b, c, x, y, z, m, n, value)
}

2.2 常量

const PI = 3.14
const (
    StatusOK = 200
    StatusNotFound = 404
)

2.3 输入输出

package main

import "fmt"

func main() {
    // 输出
    fmt.Println("Hello")           // 自动换行
    fmt.Print("Hello")             // 不换行
    fmt.Printf("数字: %d\n", 42)   // 格式化输出
    
    // 输入
    var name string
    fmt.Print("请输入姓名: ")
    fmt.Scan(&name)               // 注意要传地址
    fmt.Printf("你好, %s!\n", name)
}

2.4 注释

// 单行注释

/*
多行注释
可以写多行
*/

3. 数据类型

3.1 基本类型

package main

import "fmt"

func main() {
    // 布尔类型
    var isTrue bool = true
    
    // 整数类型
    var age int = 25
    var small int8 = 127          // -128 到 127
    var big uint64 = 123456789    // 无符号整数
    var b byte = 255              // byte 是 uint8 的别名
    var r rune = '中'             // rune 是 int32 的别名,用于表示 Unicode
    
    // 浮点类型
    var pi float32 = 3.14
    var e float64 = 2.718281828
    
    // 字符串
    var name string = "张三"
    str := "Hello" + " " + "World"  // 字符串拼接
    
    // 复数(不常用)
    var complex1 complex64 = 1 + 2i
    
    fmt.Println(isTrue, age, small, big, b, r, pi, e, name, str, complex1)
}

3.2 类型转换

package main

import (
    "fmt"
    "strconv"
)

func main() {
    // 数值类型转换(必须显式转换)
    var a int = 10
    var b float64 = float64(a)
    var c int = int(b)
    
    // 字符串转数字
    num, err := strconv.Atoi("123")
    if err != nil {
        fmt.Println("转换失败")
    }
    
    // 数字转字符串
    str := strconv.Itoa(456)
    
    // 字符串转浮点数
    f, _ := strconv.ParseFloat("3.14", 64)
    
    // 布尔值转换
    boolVal, _ := strconv.ParseBool("true")
    
    fmt.Println(a, b, c, num, str, f, boolVal)
}

3.3 格式化符号速查表

符号说明示例
%v默认格式fmt.Printf("%v", 42)
%+v结构体带字段名fmt.Printf("%+v", person)
%#vGo语法格式fmt.Printf("%#v", []int{1,2})
%T类型fmt.Printf("%T", 42)int
%t布尔值fmt.Printf("%t", true)
%d十进制整数fmt.Printf("%d", 42)
%b二进制fmt.Printf("%b", 5)101
%x十六进制(小写)fmt.Printf("%x", 255)ff
%f浮点数fmt.Printf("%.2f", 3.14159)3.14
%s字符串fmt.Printf("%s", "hello")
%q带引号字符串fmt.Printf("%q", "hello")"hello"
%p指针地址fmt.Printf("%p", &a)

4. 运算符与控制流

4.1 运算符

package main

import "fmt"

func main() {
    a, b := 10, 3
    
    // 算术运算符
    fmt.Println(a + b)  // 13
    fmt.Println(a - b)  // 7
    fmt.Println(a * b)  // 30
    fmt.Println(a / b)  // 3 (整数除法)
    fmt.Println(a % b)  // 1 (取余)
    
    // 关系运算符
    fmt.Println(a == b) // false
    fmt.Println(a != b) // true
    fmt.Println(a > b)  // true
    fmt.Println(a >= b) // true
    
    // 逻辑运算符
    fmt.Println(true && false) // false (与)
    fmt.Println(true || false) // true (或)
    fmt.Println(!true)         // false (非)
    
    // 自增自减(只能后置)
    a++
    b--
    fmt.Println(a, b) // 11 2
    
    // 赋值运算符
    c := 10
    c += 5  // c = c + 5
    c -= 2  // c = c - 2
    c *= 2  // c = c * 2
    fmt.Println(c) // 26
}

4.2 if-else

package main

import "fmt"

func main() {
    score := 85
    
    // 基本 if-else
    if score >= 90 {
        fmt.Println("优秀")
    } else if score >= 60 {
        fmt.Println("及格")
    } else {
        fmt.Println("不及格")
    }
    
    // if 可以包含初始化语句
    if age := 20; age >= 18 {
        fmt.Println("成年人")
    } // 注意:age 只在 if 块内有效
}

4.3 switch

package main

import "fmt"

func main() {
    day := 3
    
    // 基本 switch
    switch day {
    case 1:
        fmt.Println("星期一")
    case 2:
        fmt.Println("星期二")
    case 3:
        fmt.Println("星期三")
    default:
        fmt.Println("其他")
    }
    
    // 多条件匹配
    switch day {
    case 1, 2, 3, 4, 5:
        fmt.Println("工作日")
    case 6, 7:
        fmt.Println("周末")
    }
    
    // 无表达式的 switch
    score := 85
    switch {
    case score >= 90:
        fmt.Println("优秀")
    case score >= 60:
        fmt.Println("及格")
    default:
        fmt.Println("不及格")
    }
    
    // switch 初始化
    switch grade := "B"; grade {
    case "A":
        fmt.Println("90-100")
    case "B":
        fmt.Println("80-89")
    default:
        fmt.Println("其他")
    }
}

4.4 for 循环

package main

import "fmt"

func main() {
    // 标准 for 循环
    for i := 0; i < 5; i++ {
        fmt.Println(i)
    }
    
    // while 风格(Go 没有 while 关键字)
    j := 0
    for j < 5 {
        fmt.Println(j)
        j++
    }
    
    // 无限循环
    count := 0
    for {
        count++
        if count > 3 {
            break  // 跳出循环
        }
        if count == 2 {
            continue  // 跳过本次
        }
        fmt.Println(count)
    }
    
    // range 遍历
    nums := []int{10, 20, 30}
    for index, value := range nums {
        fmt.Printf("索引%d: 值%d\n", index, value)
    }
    
    // 只要值
    for _, value := range nums {
        fmt.Println(value)
    }
    
    // 只要索引
    for index := range nums {
        fmt.Println(index)
    }
    
    // 遍历字符串
    for i, char := range "Hello" {
        fmt.Printf("%d: %c\n", i, char)
    }
}

5. 函数

5.1 基本函数

package main

import "fmt"

// 无返回值
func sayHello() {
    fmt.Println("Hello")
}

// 有参数和返回值
func add(a int, b int) int {
    return a + b
}

// 参数类型相同可以简写
func multiply(a, b int) int {
    return a * b
}

// 多返回值
func swap(a, b int) (int, int) {
    return b, a
}

// 命名返回值
func divide(a, b float64) (result float64, err error) {
    if b == 0 {
        err = fmt.Errorf("除数不能为0")
        return  // 自动返回 result 和 err
    }
    result = a / b
    return
}

func main() {
    sayHello()
    
    sum := add(3, 5)
    fmt.Println(sum)
    
    x, y := swap(1, 2)
    fmt.Println(x, y)
    
    result, err := divide(10, 2)
    if err != nil {
        fmt.Println("错误:", err)
    } else {
        fmt.Println("结果:", result)
    }
}

5.2 可变参数

package main

import "fmt"

// ...表示可变参数,类型是切片
func sum(numbers ...int) int {
    total := 0
    for _, num := range numbers {
        total += num
    }
    return total
}

func main() {
    fmt.Println(sum(1, 2, 3))        // 6
    fmt.Println(sum(1, 2, 3, 4, 5))  // 15
    
    // 传递切片需要展开
    nums := []int{10, 20, 30}
    fmt.Println(sum(nums...))        // 60
}

5.3 匿名函数与闭包

package main

import "fmt"

func main() {
    // 匿名函数
    add := func(a, b int) int {
        return a + b
    }
    fmt.Println(add(3, 5))  // 8
    
    // 立即执行的匿名函数
    func(msg string) {
        fmt.Println(msg)
    }("Hello!")
    
    // 闭包:函数可以访问外部变量
    counter := makeCounter()
    fmt.Println(counter())  // 1
    fmt.Println(counter())  // 2
    fmt.Println(counter())  // 3
}

func makeCounter() func() int {
    count := 0
    return func() int {
        count++
        return count
    }
}

5.4 函数作为参数

package main

import "fmt"

// 函数类型作为参数
func apply(a, b int, operation func(int, int) int) int {
    return operation(a, b)
}

func main() {
    add := func(x, y int) int { return x + y }
    multiply := func(x, y int) int { return x * y }
    
    fmt.Println(apply(3, 5, add))      // 8
    fmt.Println(apply(3, 5, multiply)) // 15
}

6. 数组与切片

6.1 数组(长度固定)

package main

import "fmt"

func main() {
    // 声明数组
    var arr1 [5]int  // [0 0 0 0 0]
    
    // 初始化
    arr2 := [5]int{1, 2, 3, 4, 5}
    arr3 := [...]int{1, 2, 3}  // 自动计算长度
    arr4 := [5]int{1: 10, 3: 20}  // 指定索引赋值: [0 10 0 20 0]
    
    // 访问和修改
    arr2[0] = 100
    fmt.Println(arr2[0])
    
    // 长度
    fmt.Println(len(arr2))  // 5
    
    // 遍历
    for i := 0; i < len(arr2); i++ {
        fmt.Println(arr2[i])
    }
    
    for index, value := range arr2 {
        fmt.Printf("arr2[%d] = %d\n", index, value)
    }
    
    fmt.Println(arr1, arr3, arr4)
}

6.2 切片(长度可变)

package main

import "fmt"

func main() {
    // 创建切片的三种方式
    
    // 方式1:直接初始化
    slice1 := []int{1, 2, 3, 4, 5}
    
    // 方式2:make创建
    slice2 := make([]int, 3)     // 长度3,容量3
    slice3 := make([]int, 3, 5)  // 长度3,容量5
    
    // 方式3:从数组切取
    arr := [5]int{1, 2, 3, 4, 5}
    slice4 := arr[1:4]  // [2 3 4],左闭右开
    slice5 := arr[:3]   // [1 2 3],省略起始索引默认0
    slice6 := arr[2:]   // [3 4 5],省略结束索引默认到末尾
    
    fmt.Println(slice1, slice2, slice3, slice4, slice5, slice6)
}

6.3 切片操作

package main

import "fmt"

func main() {
    s := []int{1, 2, 3}
    
    // 添加元素
    s = append(s, 4)        // [1 2 3 4]
    s = append(s, 5, 6, 7)  // [1 2 3 4 5 6 7]
    
    // 长度和容量
    fmt.Printf("len=%d cap=%d\n", len(s), cap(s))
    
    // 切片拼接
    s2 := []int{10, 20, 30}
    s = append(s, s2...)  // 注意...展开
    fmt.Println(s)
    
    // 删除元素(删除索引2的元素)
    s = []int{1, 2, 3, 4, 5}
    s = append(s[:2], s[3:]...)  // [1 2 4 5]
    fmt.Println(s)
    
    // 复制切片
    original := []int{1, 2, 3}
    copied := make([]int, len(original))
    copy(copied, original)
    copied[0] = 999
    fmt.Println("original:", original)  // [1 2 3]
    fmt.Println("copied:", copied)      // [999 2 3]
}

6.4 切片陷阱(重要!)

package main

import "fmt"

func main() {
    // 陷阱1:切片共享底层数组
    arr := []int{1, 2, 3, 4, 5}
    s1 := arr[0:3]  // [1 2 3]
    s2 := arr[2:5]  // [3 4 5]
    
    s1[2] = 999     // 修改s1影响了s2
    fmt.Println(arr)  // [1 2 999 4 5]
    fmt.Println(s1)   // [1 2 999]
    fmt.Println(s2)   // [999 4 5]
    
    // 陷阱2:append可能导致重新分配
    s3 := make([]int, 2, 3)  // len=2, cap=3
    s4 := s3
    s3 = append(s3, 10)  // 容量够,不会重新分配
    s4[0] = 999
    fmt.Println(s3)  // [999 0 10],受影响
    
    s3 = append(s3, 20, 30)  // 超过容量,重新分配
    s4[0] = 111
    fmt.Println(s3)  // [999 0 10 20 30],不受影响
}

7. Map映射

7.1 创建和基本操作

package main

import "fmt"

func main() {
    // 创建方式1:字面量
    scores := map[string]int{
        "Alice": 90,
        "Bob":   85,
    }
    
    // 创建方式2:make
    ages := make(map[string]int)
    
    // 添加/修改
    ages["Charlie"] = 25
    ages["Diana"] = 30
    
    // 访问
    fmt.Println(scores["Alice"])  // 90
    
    // 检查键是否存在(重要!)
    score, exists := scores["Eve"]
    if exists {
        fmt.Println("Eve的分数:", score)
    } else {
        fmt.Println("Eve不存在")
    }
    
    // 删除
    delete(scores, "Bob")
    
    // 长度
    fmt.Println("map长度:", len(scores))
    
    // 遍历(顺序不固定)
    for name, score := range scores {
        fmt.Printf("%s: %d\n", name, score)
    }
}

7.2 Map进阶操作

package main

import (
    "fmt"
    "sort"
)

func main() {
    // 有序遍历:先取键排序
    m := map[string]int{
        "c": 3,
        "a": 1,
        "b": 2,
    }
    
    keys := make([]string, 0, len(m))
    for k := range m {
        keys = append(keys, k)
    }
    sort.Strings(keys)
    
    for _, k := range keys {
        fmt.Printf("%s: %d\n", k, m[k])
    }
    
    // Map的值是切片(一对多)
    graph := make(map[string][]string)
    graph["A"] = append(graph["A"], "B", "C")
    graph["B"] = append(graph["B"], "D")
    fmt.Println(graph)  // map[A:[B C] B:[D]]
    
    // 用Map模拟Set
    set := make(map[string]struct{})
    set["apple"] = struct{}{}
    set["banana"] = struct{}{}
    
    if _, exists := set["apple"]; exists {
        fmt.Println("apple在集合中")
    }
}

8. 指针

8.1 基本概念

package main

import "fmt"

func main() {
    a := 42
    
    // &取地址,*解引用
    p := &a              // p是指向a的指针
    fmt.Println(p)       // 0xc000012090(地址)
    fmt.Println(*p)      // 42(解引用得到值)
    
    *p = 100             // 通过指针修改a
    fmt.Println(a)       // 100
    
    // new函数:分配内存并返回指针
    q := new(int)        // q是*int,值为0
    *q = 200
    fmt.Println(*q)      // 200
    
    // 没有指针运算(安全)
    // p++  // 这是不允许的
}

8.2 值传递 vs 指针传递

package main

import "fmt"

// 值传递:不影响原变量
func modifyValue(x int) {
    x = 100
}

// 指针传递:影响原变量
func modifyPointer(x *int) {
    *x = 100
}

func main() {
    a := 1
    modifyValue(a)
    fmt.Println(a)  // 1,没变
    
    b := 1
    modifyPointer(&b)
    fmt.Println(b)  // 100,改变了
}

8.3 什么时候用指针

package main

import "fmt"

type BigStruct struct {
    Data [1000000]int
}

// 值传递:复制整个结构体,慢且占内存
func processByValue(s BigStruct) {
    s.Data[0] = 1  // 不影响原数据
}

// 指针传递:只复制一个指针,快
func processByPointer(s *BigStruct) {
    s.Data[0] = 1  // 修改原数据
}

func main() {
    s := BigStruct{}
    
    // 规则:
    // 1. 需要修改原变量 → 用指针
    // 2. 结构体很大 → 用指针
    // 3. 小的基本类型 → 用值传递
    
    processByPointer(&s)
    fmt.Println(s.Data[0])  // 1
}

9. 结构体

9.1 基本定义

package main

import "fmt"

// 定义结构体
type Person struct {
    Name string
    Age  int
}

type Student struct {
    Name  string
    Age   int
    Grade int
}

func main() {
    // 创建方式1:按字段顺序
    p1 := Person{"Alice", 25}
    
    // 创建方式2:指定字段名(推荐)
    p2 := Person{
        Name: "Bob",
        Age:  30,
    }
    
    // 创建方式3:零值初始化
    var p3 Person  // {Name:"" Age:0}
    
    // 创建方式4:指针
    p4 := &Person{Name: "Charlie", Age: 35}
    
    // 访问字段
    fmt.Println(p1.Name)
    fmt.Println(p4.Age)  // 指针自动解引用,不需要(*p4).Age
    
    // 修改字段
    p1.Age = 26
    p4.Name = "Charles"
    
    fmt.Println(p1, p2, p3, p4)
}

9.2 匿名字段与嵌套

package main

import "fmt"

type Address struct {
    City  string
    Street string
}

type Person struct {
    Name string
    Age  int
    Address  // 匿名嵌套
}

func main() {
    p := Person{
        Name: "Alice",
        Age:  25,
        Address: Address{
            City:  "北京",
            Street: "长安街",
        },
    }
    
    // 访问嵌套字段
    fmt.Println(p.Address.City)  // 完整路径
    fmt.Println(p.City)          // 字段提升,可以直接访问
}

9.3 结构体标签(用于JSON等)

package main

import (
    "encoding/json"
    "fmt"
)

type User struct {
    ID       int    `json:"id"`
    Username string `json:"username"`
    Password string `json:"-"`              // 忽略此字段
    Email    string `json:"email,omitempty"` // 空值不输出
}

func main() {
    u := User{
        ID:       1,
        Username: "alice",
        Password: "secret",
        Email:    "",
    }
    
    data, _ := json.Marshal(u)
    fmt.Println(string(data))
    // {"id":1,"username":"alice"}
    // 注意:Password被忽略,Email为空不输出
}

10. 方法

10.1 基本方法

package main

import (
    "fmt"
    "math"
)

type Point struct {
    X, Y float64
}

// 值接收者:不修改原结构体
func (p Point) Distance() float64 {
    return math.Sqrt(p.X*p.X + p.Y*p.Y)
}

// 指针接收者:可以修改原结构体
func (p *Point) Move(dx, dy float64) {
    p.X += dx
    p.Y += dy
}

func main() {
    p := Point{X: 3, Y: 4}
    
    fmt.Println(p.Distance())  // 5
    
    p.Move(1, 1)
    fmt.Println(p)  // {4 5}
}

10.2 何时用指针接收者

package main

import "fmt"

type Counter struct {
    count int
}

// 规则:
// 1. 需要修改接收者 → 用指针
// 2. 接收者很大 → 用指针
// 3. 保持一致性:如果有一个方法用指针,其他也用指针

func (c *Counter) Increment() {
    c.count++
}

func (c *Counter) Value() int {
    return c.count
}

func main() {
    c := Counter{}
    c.Increment()
    c.Increment()
    fmt.Println(c.Value())  // 2
}

11. 接口

11.1 基本概念

package main

import (
    "fmt"
    "math"
)

// 定义接口
type Shape interface {
    Area() float64
    Perimeter() float64
}

// 实现接口(不需要显式声明)
type Circle struct {
    Radius float64
}

func (c Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}

func (c Circle) Perimeter() float64 {
    return 2 * math.Pi * c.Radius
}

type Rectangle struct {
    Width, Height float64
}

func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

func (r Rectangle) Perimeter() float64 {
    return 2 * (r.Width + r.Height)
}

// 接受接口类型的函数
func printShapeInfo(s Shape) {
    fmt.Printf("面积: %.2f, 周长: %.2f\n", s.Area(), s.Perimeter())
}

func main() {
    c := Circle{Radius: 5}
    r := Rectangle{Width: 3, Height: 4}
    
    printShapeInfo(c)  // 面积: 78.54, 周长: 31.42
    printShapeInfo(r)  // 面积: 12.00, 周长: 14.00
}

11.2 空接口

package main

import "fmt"

// interface{} 或 any 可以接收任何类型
func printAnything(v interface{}) {
    fmt.Println(v)
}

func main() {
    printAnything(42)
    printAnything("hello")
    printAnything([]int{1, 2, 3})
    
    // Go 1.18+ 可以用 any 代替 interface{}
    var x any = "world"
    fmt.Println(x)
}

11.3 类型断言

package main

import "fmt"

type Shape interface {
    Area() float64
}

type Circle struct {
    Radius float64
}

func (c Circle) Area() float64 {
    return 3.14 * c.Radius * c.Radius
}

type Rectangle struct {
    Width, Height float64
}

func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

func describe(s Shape) {
    // 方式1:单个类型断言
    if c, ok := s.(Circle); ok {
        fmt.Printf("圆,半径=%.2f\n", c.Radius)
        return
    }
    
    // 方式2:type switch
    switch v := s.(type) {
    case Circle:
        fmt.Printf("圆,半径=%.2f\n", v.Radius)
    case Rectangle:
        fmt.Printf("矩形,宽=%.2f,高=%.2f\n", v.Width, v.Height)
    default:
        fmt.Println("未知形状")
    }
}

func main() {
    shapes := []Shape{
        Circle{Radius: 5},
        Rectangle{Width: 3, Height: 4},
    }
    
    for _, s := range shapes {
        describe(s)
    }
}

11.4 接口组合

package main

import "fmt"

type Reader interface {
    Read() string
}

type Writer interface {
    Write(string)
}

// 接口可以组合
type ReadWriter interface {
    Reader
    Writer
}

type File struct {
    content string
}

func (f *File) Read() string {
    return f.content
}

func (f *File) Write(s string) {
    f.content = s
}

func main() {
    var rw ReadWriter = &File{}
    rw.Write("Hello")
    fmt.Println(rw.Read())
}

12. 错误处理

12.1 基本错误处理

package main

import (
    "errors"
    "fmt"
)

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

func main() {
    result, err := divide(10, 0)
    if err != nil {
        fmt.Println("错误:", err)
        return
    }
    fmt.Println("结果:", result)
}

12.2 自定义错误

package main

import "fmt"

// 实现error接口
type ValidationError struct {
    Field   string
    Message string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("字段'%s'验证失败: %s", e.Field, e.Message)
}

func validateAge(age int) error {
    if age < 0 {
        return &ValidationError{
            Field:   "age",
            Message: "年龄不能为负数",
        }
    }
    if age > 150 {
        return &ValidationError{
            Field:   "age",
            Message: "年龄不合理",
        }
    }
    return nil
}

func main() {
    if err := validateAge(-5); err != nil {
        fmt.Println(err)  // 字段'age'验证失败: 年龄不能为负数
    }
}

12.3 错误包装(Go 1.13+)

package main

import (
    "errors"
    "fmt"
)

var ErrNotFound = errors.New("not found")

func findUser(id int) error {
    if id > 100 {
        return ErrNotFound
    }
    return nil
}

func getUser(id int) error {
    err := findUser(id)
    if err != nil {
        return fmt.Errorf("getUser失败: %w", err)  // %w包装错误
    }
    return nil
}

func main() {
    err := getUser(200)
    if err != nil {
        fmt.Println(err)
        
        // errors.Is:检查错误链
        if errors.Is(err, ErrNotFound) {
            fmt.Println("用户未找到")
        }
    }
}

12.4 panic 和 recover

package main

import "fmt"

func safeDivide(a, b int) {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("捕获panic:", r)
        }
    }()
    
    result := a / b  // b=0时会panic
    fmt.Println("结果:", result)
}

func main() {
    safeDivide(10, 0)  // 捕获panic: runtime error: integer divide by zero
    fmt.Println("程序继续运行")
}

13. defer关键字

13.1 基本用法

package main

import "fmt"

func main() {
    // defer延迟执行,按LIFO顺序
    defer fmt.Println("1")
    defer fmt.Println("2")
    defer fmt.Println("3")
    fmt.Println("主函数")
    
    // 输出:
    // 主函数
    // 3
    // 2
    // 1
}

13.2 资源清理

package main

import (
    "fmt"
    "os"
)

func writeFile(filename, content string) error {
    f, err := os.Create(filename)
    if err != nil {
        return err
    }
    defer f.Close()  // 确保函数结束时关闭文件
    
    _, err = f.WriteString(content)
    return err
}

func main() {
    err := writeFile("test.txt", "Hello World")
    if err != nil {
        fmt.Println("写入失败:", err)
    } else {
        fmt.Println("写入成功")
    }
}

13.3 defer的陷阱

package main

import "fmt"

func main() {
    // 陷阱1:defer注册时就确定参数值
    x := 0
    defer fmt.Println("值拷贝:", x)  // 输出: 值拷贝: 0
    x = 10
    
    // 陷阱2:闭包捕获变量
    y := 0
    defer func() {
        fmt.Println("闭包:", y)  // 输出: 闭包: 10
    }()
    y = 10
    
    // 输出顺序(LIFO):
    // 闭包: 10
    // 值拷贝: 0
}

14. 并发编程

14.1 Goroutine基础

package main

import (
    "fmt"
    "time"
)

func sayHello(name string) {
    for i := 0; i < 3; i++ {
        fmt.Printf("%s: Hello %d\n", name, i)
        time.Sleep(100 * time.Millisecond)
    }
}

func main() {
    // 启动goroutine
    go sayHello("goroutine-1")
    go sayHello("goroutine-2")
    
    // 主函数也执行
    sayHello("main")
    
    // 等待goroutine完成(简单方式)
    time.Sleep(500 * time.Millisecond)
}

14.2 WaitGroup

package main

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

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done()  // 完成时计数-1
    
    fmt.Printf("Worker %d 开始\n", id)
    time.Sleep(time.Second)
    fmt.Printf("Worker %d 完成\n", id)
}

func main() {
    var wg sync.WaitGroup
    
    for i := 1; i <= 5; i++ {
        wg.Add(1)  // 计数+1
        go worker(i, &wg)
    }
    
    wg.Wait()  // 等待计数归零
    fmt.Println("所有worker完成")
}

14.3 Mutex互斥锁

package main

import (
    "fmt"
    "sync"
)

type SafeCounter struct {
    mu    sync.Mutex
    count int
}

func (c *SafeCounter) Increment() {
    c.mu.Lock()
    c.count++
    c.mu.Unlock()
}

func (c *SafeCounter) Value() int {
    c.mu.Lock()
    defer c.mu.Unlock()
    return c.count
}

func main() {
    counter := &SafeCounter{}
    var wg sync.WaitGroup
    
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            counter.Increment()
        }()
    }
    
    wg.Wait()
    fmt.Println("计数:", counter.Value())  // 1000
}

14.4 sync.Once

package main

import (
    "fmt"
    "sync"
)

var once sync.Once

func initialize() {
    fmt.Println("初始化(只执行一次)")
}

func main() {
    var wg sync.WaitGroup
    
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            once.Do(initialize)  // 多次调用,只执行一次
        }()
    }
    
    wg.Wait()
}

15. Channel通道

15.1 基本用法

package main

import "fmt"

func main() {
    // 创建channel
    ch := make(chan int)
    
    // 发送数据(在goroutine中,否则会死锁)
    go func() {
        ch <- 42  // 发送
    }()
    
    // 接收数据
    value := <-ch  // 接收
    fmt.Println(value)  // 42
}

15.2 缓冲通道

package main

import "fmt"

func main() {
    // 无缓冲:发送和接收必须同时准备好
    ch1 := make(chan int)
    
    // 有缓冲:缓冲区满之前发送不阻塞
    ch2 := make(chan int, 3)
    
    ch2 <- 1
    ch2 <- 2
    ch2 <- 3
    // ch2 <- 4  // 这里会阻塞
    
    fmt.Println(<-ch2)  // 1
    fmt.Println(<-ch2)  // 2
    
    _ = ch1
}

15.3 关闭通道与range

package main

import "fmt"

func producer(ch chan int) {
    for i := 0; i < 5; i++ {
        ch <- i
    }
    close(ch)  // 关闭通道
}

func main() {
    ch := make(chan int)
    go producer(ch)
    
    // range持续接收直到通道关闭
    for value := range ch {
        fmt.Println(value)
    }
    
    // 从已关闭的通道接收,得到零值
    v, ok := <-ch
    fmt.Println(v, ok)  // 0 false
}

15.4 单向通道

package main

import "fmt"

// 只写通道
func producer(ch chan<- int) {
    for i := 0; i < 5; i++ {
        ch <- i
    }
    close(ch)
}

// 只读通道
func consumer(ch <-chan int) {
    for value := range ch {
        fmt.Println("收到:", value)
    }
}

func main() {
    ch := make(chan int)
    go producer(ch)
    consumer(ch)
}

15.5 select多路复用

package main

import (
    "fmt"
    "time"
)

func main() {
    ch1 := make(chan string)
    ch2 := make(chan string)
    
    go func() {
        time.Sleep(1 * time.Second)
        ch1 <- "来自ch1"
    }()
    
    go func() {
        time.Sleep(2 * time.Second)
        ch2 <- "来自ch2"
    }()
    
    // select等待多个channel
    for i := 0; i < 2; i++ {
        select {
        case msg1 := <-ch1:
            fmt.Println(msg1)
        case msg2 := <-ch2:
            fmt.Println(msg2)
        }
    }
    
    // 超时控制
    select {
    case msg := <-ch1:
        fmt.Println(msg)
    case <-time.After(3 * time.Second):
        fmt.Println("超时")
    }
}

15.6 Worker Pool模式

package main

import (
    "fmt"
    "sync"
)

func worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {
    defer wg.Done()
    for job := range jobs {
        fmt.Printf("Worker %d 处理任务 %d\n", id, job)
        results <- job * 2
    }
}

func main() {
    jobs := make(chan int, 10)
    results := make(chan int, 10)
    var wg sync.WaitGroup
    
    // 启动3个worker
    for w := 1; w <= 3; w++ {
        wg.Add(1)
        go worker(w, jobs, results, &wg)
    }
    
    // 发送任务
    for j := 1; j <= 9; j++ {
        jobs <- j
    }
    close(jobs)
    
    // 等待所有worker完成
    go func() {
        wg.Wait()
        close(results)
    }()
    
    // 收集结果
    for result := range results {
        fmt.Println("结果:", result)
    }
}

16. Context上下文

16.1 基本用法

package main

import (
    "context"
    "fmt"
    "time"
)

func worker(ctx context.Context, name string) {
    for {
        select {
        case <-ctx.Done():
            fmt.Printf("%s: 收到取消信号\n", name)
            return
        default:
            fmt.Printf("%s: 工作中...\n", name)
            time.Sleep(500 * time.Millisecond)
        }
    }
}

func main() {
    // WithCancel: 手动取消
    ctx, cancel := context.WithCancel(context.Background())
    
    go worker(ctx, "worker-1")
    
    time.Sleep(2 * time.Second)
    cancel()  // 取消
    time.Sleep(1 * time.Second)
}

16.2 超时控制

package main

import (
    "context"
    "fmt"
    "time"
)

func doWork(ctx context.Context) {
    select {
    case <-time.After(3 * time.Second):
        fmt.Println("工作完成")
    case <-ctx.Done():
        fmt.Println("超时,取消工作")
    }
}

func main() {
    // WithTimeout: 超时自动取消
    ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
    defer cancel()
    
    doWork(ctx)
}

16.3 传递数据

package main

import (
    "context"
    "fmt"
)

func process(ctx context.Context) {
    userID := ctx.Value("userID")
    fmt.Println("处理用户请求, userID:", userID)
}

func main() {
    ctx := context.WithValue(context.Background(), "userID", 12345)
    process(ctx)
}

17. 字符串处理

17.1 strings包

package main

import (
    "fmt"
    "strings"
)

func main() {
    s := "Hello, World!"
    
    // 判断
    fmt.Println(strings.Contains(s, "World"))   // true
    fmt.Println(strings.HasPrefix(s, "Hello"))  // true
    fmt.Println(strings.HasSuffix(s, "!"))      // true
    
    // 查找
    fmt.Println(strings.Index(s, "World"))      // 7
    fmt.Println(strings.Count(s, "l"))          // 3
    
    // 转换
    fmt.Println(strings.ToUpper(s))             // HELLO, WORLD!
    fmt.Println(strings.ToLower(s))             // hello, world!
    
    // 替换
    fmt.Println(strings.Replace(s, "World", "Go", 1))  // Hello, Go!
    fmt.Println(strings.ReplaceAll(s, "l", "L"))       // HeLLo, WorLd!
    
    // 分割和连接
    parts := strings.Split("a,b,c", ",")
    fmt.Println(parts)  // [a b c]
    
    joined := strings.Join([]string{"a", "b", "c"}, "-")
    fmt.Println(joined)  // a-b-c
    
    // 去除空格
    fmt.Println(strings.TrimSpace("  hello  "))  // hello
    fmt.Println(strings.Trim("!!hello!!", "!"))  // hello
    
    // 重复
    fmt.Println(strings.Repeat("Go", 3))  // GoGoGo
}

17.2 字符串与字节

package main

import "fmt"

func main() {
    s := "Hello, 世界"
    
    // 字符串长度(字节数)
    fmt.Println(len(s))  // 13
    
    // 按字符(rune)遍历
    for i, ch := range s {
        fmt.Printf("索引%d: %c\n", i, ch)
    }
    
    // 转为rune切片(正确处理中文)
    runes := []rune(s)
    fmt.Println(len(runes))  // 9(字符数)
    fmt.Println(string(runes[7:]))  // 世界
}

17.3 字符串拼接

package main

import (
    "fmt"
    "strings"
)

func main() {
    // 方式1:+ 运算符(简单场景)
    s1 := "Hello" + " " + "World"
    
    // 方式2:fmt.Sprintf(需要格式化)
    s2 := fmt.Sprintf("%s %d", "Number", 42)
    
    // 方式3:strings.Builder(高效,大量拼接)
    var builder strings.Builder
    for i := 0; i < 100; i++ {
        builder.WriteString("hello ")
    }
    s3 := builder.String()
    
    fmt.Println(s1, s2, len(s3))
}

18. 文件操作

18.1 写文件

package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    // 方式1:简单写入
    err := os.WriteFile("simple.txt", []byte("Hello World"), 0644)
    if err != nil {
        fmt.Println("写入失败:", err)
    }
    
    // 方式2:Create + Write
    f, err := os.Create("test.txt")
    if err != nil {
        panic(err)
    }
    defer f.Close()
    
    f.WriteString("第一行\n")
    
    // 方式3:带缓冲写入(推荐大量写入)
    writer := bufio.NewWriter(f)
    writer.WriteString("第二行\n")
    writer.WriteString("第三行\n")
    writer.Flush()  // 别忘了
}

18.2 读文件

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
)

func main() {
    // 方式1:一次性读取全部
    data, err := os.ReadFile("test.txt")
    if err != nil {
        panic(err)
    }
    fmt.Println(string(data))
    
    // 方式2:逐行读取
    f, err := os.Open("test.txt")
    if err != nil {
        panic(err)
    }
    defer f.Close()
    
    scanner := bufio.NewScanner(f)
    lineNum := 1
    for scanner.Scan() {
        fmt.Printf("第%d行: %s\n", lineNum, scanner.Text())
        lineNum++
    }
    
    // 方式3:用Reader
    f.Seek(0, io.SeekStart)  // 回到开头
    reader := bufio.NewReader(f)
    for {
        line, err := reader.ReadString('\n')
        if err != nil {
            break
        }
        fmt.Print(line)
    }
}

18.3 文件是否存在

package main

import (
    "fmt"
    "os"
)

func fileExists(filename string) bool {
    _, err := os.Stat(filename)
    return !os.IsNotExist(err)
}

func main() {
    if fileExists("test.txt") {
        fmt.Println("文件存在")
    } else {
        fmt.Println("文件不存在")
    }
}

19. JSON处理

19.1 结构体与JSON

package main

import (
    "encoding/json"
    "fmt"
)

type User struct {
    ID       int      `json:"id"`
    Username string   `json:"username"`
    Email    string   `json:"email,omitempty"` // 空值不输出
    Password string   `json:"-"`               // 忽略
    Tags     []string `json:"tags"`
}

func main() {
    // 结构体 → JSON(序列化)
    user := User{
        ID:       1,
        Username: "alice",
        Email:    "",
        Password: "secret",
        Tags:     []string{"admin", "user"},
    }
    
    jsonBytes, _ := json.Marshal(user)
    fmt.Println(string(jsonBytes))
    // {"id":1,"username":"alice","tags":["admin","user"]}
    
    // 美化输出
    prettyJSON, _ := json.MarshalIndent(user, "", "  ")
    fmt.Println(string(prettyJSON))
    
    // JSON → 结构体(反序列化)
    jsonStr := `{"id":2,"username":"bob","tags":["developer"]}`
    var user2 User
    json.Unmarshal([]byte(jsonStr), &user2)
    fmt.Printf("%+v\n", user2)
}

19.2 动态JSON

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    jsonStr := `{
        "name": "Alice",
        "age": 25,
        "scores": [90, 85, 92]
    }`
    
    // 用map处理
    var data map[string]interface{}
    json.Unmarshal([]byte(jsonStr), &data)
    
    fmt.Println(data["name"])    // Alice
    fmt.Println(data["age"])     // 25
    
    // scores是[]interface{}类型
    scores := data["scores"].([]interface{})
    fmt.Println(scores[0])       // 90
}

20. HTTP编程

20.1 HTTP客户端

package main

import (
    "fmt"
    "io"
    "net/http"
    "time"
)

func main() {
    // 简单GET请求
    resp, err := http.Get("https://httpbin.org/get")
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
    
    body, _ := io.ReadAll(resp.Body)
    fmt.Println(string(body))
    
    // 自定义请求
    client := &http.Client{
        Timeout: 10 * time.Second,
    }
    
    req, _ := http.NewRequest("GET", "https://httpbin.org/get", nil)
    req.Header.Set("Authorization", "Bearer token123")
    
    resp2, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp2.Body.Close()
    
    fmt.Println("状态码:", resp2.StatusCode)
}

20.2 HTTP服务端

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "time"
)

type Response struct {
    Message string `json:"message"`
    Time    string `json:"time"`
}

func helloHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    
    resp := Response{
        Message: "Hello, World!",
        Time:    time.Now().Format(time.RFC3339),
    }
    json.NewEncoder(w).Encode(resp)
}

func userHandler(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case "GET":
        fmt.Fprintf(w, "获取用户列表")
    case "POST":
        fmt.Fprintf(w, "创建用户")
    default:
        http.Error(w, "方法不允许", http.StatusMethodNotAllowed)
    }
}

func main() {
    http.HandleFunc("/hello", helloHandler)
    http.HandleFunc("/users", userHandler)
    
    fmt.Println("服务器启动在 http://localhost:8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

21. 包管理

21.1 创建模块

Bash

# 初始化模块
mkdir myproject
cd myproject
go mod init myproject

# 项目结构
myproject/
├── go.mod
├── main.go
├── pkg/
│   └── utils/
│       └── helper.go
└── internal/
    └── service/
        └── user.go

21.2 包的定义和使用

// pkg/utils/helper.go
package utils

import "strings"

// 大写开头 = 导出(public)
func ToUpperCase(s string) string {
    return strings.ToUpper(s)
}

// 小写开头 = 未导出(private)
func toLowerCase(s string) string {
    return strings.ToLower(s)
}
// main.go
package main

import (
    "fmt"
    "myproject/pkg/utils"
)

func main() {
    result := utils.ToUpperCase("hello")
    fmt.Println(result)  // HELLO
    
    // utils.toLowerCase("WORLD")  // 错误:未导出
}

21.3 依赖管理

Bash

# 添加依赖
go get github.com/gin-gonic/gin

# 整理依赖
go mod tidy

# 查看依赖
go list -m all

# 下载依赖到本地
go mod download

22. 测试

22.1 基本测试

// math.go
package math

func Add(a, b int) int {
    return a + b
}

func Divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, fmt.Errorf("除数不能为0")
    }
    return a / b, nil
}
// math_test.go
package math

import "testing"

func TestAdd(t *testing.T) {
    result := Add(2, 3)
    if result != 5 {
        t.Errorf("Add(2, 3) = %d; want 5", result)
    }
}

// 表驱动测试(推荐)
func TestAddTable(t *testing.T) {
    tests := []struct {
        name     string
        a, b     int
        expected int
    }{
        {"正数", 2, 3, 5},
        {"负数", -1, -2, -3},
        {"零值", 0, 0, 0},
    }
    
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            result := Add(tt.a, tt.b)
            if result != tt.expected {
                t.Errorf("got %d, want %d", result, tt.expected)
            }
        })
    }
}

// 基准测试
func BenchmarkAdd(b *testing.B) {
    for i := 0; i < b.N; i++ {
        Add(1, 2)
    }
}

Bash

# 运行测试
go test

# 详细输出
go test -v

# 基准测试
go test -bench=.

# 覆盖率
go test -cover

23. 常用标准库

23.1 time包

package main

import (
    "fmt"
    "time"
)

func main() {
    // 当前时间
    now := time.Now()
    fmt.Println(now)
    
    // 格式化(Go特定:用2006-01-02 15:04:05)
    fmt.Println(now.Format("2006-01-02 15:04:05"))
    fmt.Println(now.Format("2006/01/02"))
    
    // 解析
    t, _ := time.Parse("2006-01-02", "2024-12-25")
    fmt.Println(t)
    
    // 时间运算
    future := now.Add(24 * time.Hour)
    fmt.Println(future)
    
    duration := future.Sub(now)
    fmt.Println(duration)  // 24h0m0s
    
    // 睡眠
    time.Sleep(1 * time.Second)
    
    // 定时器
    timer := time.NewTimer(2 * time.Second)
    <-timer.C
    fmt.Println("2秒后执行")
    
    // 定时执行
    ticker := time.NewTicker(1 * time.Second)
    defer ticker.Stop()
    
    count := 0
    for range ticker.C {
        count++
        fmt.Println("tick", count)
        if count >= 3 {
            break
        }
    }
}

23.2 sort包

package main

import (
    "fmt"
    "sort"
)

func main() {
    // 排序整数
    nums := []int{5, 2, 8, 1, 9}
    sort.Ints(nums)
    fmt.Println(nums)  // [1 2 5 8 9]
    
    // 排序字符串
    strs := []string{"banana", "apple", "cherry"}
    sort.Strings(strs)
    fmt.Println(strs)  // [apple banana cherry]
    
    // 自定义排序
    type Person struct {
        Name string
        Age  int
    }
    
    people := []Person{
        {"Bob", 25},
        {"Alice", 30},
        {"Charlie", 20},
    }
    
    sort.Slice(people, func(i, j int) bool {
        return people[i].Age < people[j].Age
    })
    
    fmt.Println(people)
    // [{Charlie 20} {Bob 25} {Alice 30}]
}

23.3 regexp包

package main

import (
    "fmt"
    "regexp"
)

func main() {
    // 编译正则表达式
    re := regexp.MustCompile(`\d+`)
    
    // 匹配
    fmt.Println(re.MatchString("hello123"))  // true
    
    // 查找
    fmt.Println(re.FindString("abc123def"))  // 123
    fmt.Println(re.FindAllString("a1b2c3", -1))  // [1 2 3]
    
    // 替换
    result := re.ReplaceAllString("a1b2c3", "X")
    fmt.Println(result)  // aXbXcX
}

24. 泛型(Go 1.18+)

24.1 泛型函数

package main

import "fmt"

// 泛型函数
func Max[T comparable](a, b T) T {
    if a > b {
        return a
    }
    return b
}

// 类型约束
type Number interface {
    int | int64 | float64
}

func Sum[T Number](slice []T) T {
    var sum T
    for _, v := range slice {
        sum += v
    }
    return sum
}

func main() {
    fmt.Println(Max(3, 5))       // 5
    fmt.Println(Max("a", "z"))   // z
    
    fmt.Println(Sum([]int{1, 2, 3, 4, 5}))        // 15
    fmt.Println(Sum([]float64{1.1, 2.2, 3.3}))    // 6.6
}

24.2 泛型结构体

package main

import "fmt"

type Stack[T any] struct {
    items []T
}

func (s *Stack[T]) Push(item T) {
    s.items = append(s.items, item)
}

func (s *Stack[T]) Pop() (T, bool) {
    var zero T
    if len(s.items) == 0 {
        return zero, false
    }
    item := s.items[len(s.items)-1]
    s.items = s.items[:len(s.items)-1]
    return item, true
}

func main() {
    // 整数栈
    intStack := &Stack[int]{}
    intStack.Push(1)
    intStack.Push(2)
    v, _ := intStack.Pop()
    fmt.Println(v)  // 2
    
    // 字符串栈
    strStack := &Stack[string]{}
    strStack.Push("hello")
    strStack.Push("world")
    s, _ := strStack.Pop()
    fmt.Println(s)  // world
}

25. 示例

25.1 命令行TODO应用

// todo.go
package main

import (
    "bufio"
    "encoding/json"
    "fmt"
    "os"
    "strconv"
    "strings"
)

type Task struct {
    ID     int    `json:"id"`
    Title  string `json:"title"`
    Done   bool   `json:"done"`
}

type TodoList struct {
    tasks []Task
    file  string
}

func NewTodoList(filename string) *TodoList {
    tl := &TodoList{file: filename}
    tl.load()
    return tl
}

func (tl *TodoList) load() {
    data, err := os.ReadFile(tl.file)
    if err != nil {
        return
    }
    json.Unmarshal(data, &tl.tasks)
}

func (tl *TodoList) save() {
    data, _ := json.MarshalIndent(tl.tasks, "", "  ")
    os.WriteFile(tl.file, data, 0644)
}

func (tl *TodoList) Add(title string) {
    id := len(tl.tasks) + 1
    tl.tasks = append(tl.tasks, Task{ID: id, Title: title})
    tl.save()
    fmt.Printf("添加任务: %s\n", title)
}

func (tl *TodoList) List() {
    for _, task := range tl.tasks {
        status := " "
        if task.Done {
            status = "✓"
        }
        fmt.Printf("[%s] %d. %s\n", status, task.ID, task.Title)
    }
}

func (tl *TodoList) Done(id int) {
    for i := range tl.tasks {
        if tl.tasks[i].ID == id {
            tl.tasks[i].Done = true
            tl.save()
            fmt.Println("任务已完成")
            return
        }
    }
    fmt.Println("任务不存在")
}

func main() {
    todo := NewTodoList("tasks.json")
    reader := bufio.NewReader(os.Stdin)
    
    for {
        fmt.Println("\n=== TODO应用 ===")
        fmt.Println("1. 添加任务")
        fmt.Println("2. 查看任务")
        fmt.Println("3. 完成任务")
        fmt.Println("4. 退出")
        fmt.Print("请选择: ")
        
        input, _ := reader.ReadString('\n')
        choice := strings.TrimSpace(input)
        
        switch choice {
        case "1":
            fmt.Print("任务名称: ")
            title, _ := reader.ReadString('\n')
            todo.Add(strings.TrimSpace(title))
        case "2":
            todo.List()
        case "3":
            fmt.Print("任务ID: ")
            idStr, _ := reader.ReadString('\n')
            id, _ := strconv.Atoi(strings.TrimSpace(idStr))
            todo.Done(id)
        case "4":
            return
        }
    }
}

25.2 简单Web API

// api.go
package main

import (
    "encoding/json"
    "log"
    "net/http"
    "strconv"
    "sync"
)

type User struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
}

var (
    users   = []User{}
    nextID  = 1
    usersMu sync.Mutex
)

func getUsers(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    usersMu.Lock()
    defer usersMu.Unlock()
    json.NewEncoder(w).Encode(users)
}

func createUser(w http.ResponseWriter, r *http.Request) {
    var user User
    if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    
    usersMu.Lock()
    user.ID = nextID
    nextID++
    users = append(users, user)
    usersMu.Unlock()
    
    w.Header().Set("Content-Type", "application/json")
    w.WriteStatus(http.StatusCreated)
    json.NewEncoder(w).Encode(user)
}

func usersHandler(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case "GET":
        getUsers(w, r)
    case "POST":
        createUser(w, r)
    default:
        http.Error(w, "方法不允许", http.StatusMethodNotAllowed)
    }
}

func main() {
    http.HandleFunc("/users", usersHandler)
    
    log.Println("服务器启动在 :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}
# 测试API
curl http://localhost:8080/users
curl -X POST -H "Content-Type: application/json" -d '{"name":"Alice"}' http://localhost:8080/users
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cllsse

富✌您吉祥

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值