Skip to content

Go语言

Go基础

Go语言特性

Go语言是由Google开发的一种静态类型、编译型语言,具有以下特点:

  • 简洁高效:语法简洁,编译速度快
  • 并发支持:内置goroutine和channel,原生支持并发
  • 垃圾回收:自动内存管理
  • 强类型:编译时类型检查
  • 跨平台:支持多种操作系统和架构

基础语法

go
package main

import (
    "fmt"
    "net/http"
)

// 结构体定义
type User struct {
    ID       int    `json:"id"`
    Username string `json:"username"`
    Email    string `json:"email"`
}

// 方法定义
func (u *User) GetFullInfo() string {
    return fmt.Sprintf("ID: %d, Username: %s, Email: %s", u.ID, u.Username, u.Email)
}

// 接口定义
type UserService interface {
    GetUser(id int) (*User, error)
    CreateUser(user *User) error
}

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

Web框架

Gin框架

Gin是一个高性能的HTTP Web框架。

基础使用

go
package main

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

type User struct {
    ID       int    `json:"id"`
    Username string `json:"username"`
    Email    string `json:"email"`
}

func main() {
    r := gin.Default()
    
    // 中间件
    r.Use(gin.Logger())
    r.Use(gin.Recovery())
    
    // 路由
    r.GET("/ping", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{
            "message": "pong",
        })
    })
    
    // 用户相关路由
    users := r.Group("/api/users")
    {
        users.GET("", getUsers)
        users.GET("/:id", getUser)
        users.POST("", createUser)
        users.PUT("/:id", updateUser)
        users.DELETE("/:id", deleteUser)
    }
    
    r.Run(":8080")
}

func getUsers(c *gin.Context) {
    users := []User{
        {ID: 1, Username: "john", Email: "[email protected]"},
        {ID: 2, Username: "jane", Email: "[email protected]"},
    }
    c.JSON(http.StatusOK, users)
}

func getUser(c *gin.Context) {
    id := c.Param("id")
    // 这里应该从数据库查询
    user := User{ID: 1, Username: "john", Email: "[email protected]"}
    c.JSON(http.StatusOK, user)
}

func createUser(c *gin.Context) {
    var user User
    if err := c.ShouldBindJSON(&user); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }
    
    // 这里应该保存到数据库
    c.JSON(http.StatusCreated, user)
}

func updateUser(c *gin.Context) {
    id := c.Param("id")
    var user User
    if err := c.ShouldBindJSON(&user); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }
    
    // 这里应该更新数据库
    c.JSON(http.StatusOK, user)
}

func deleteUser(c *gin.Context) {
    id := c.Param("id")
    // 这里应该从数据库删除
    c.JSON(http.StatusOK, gin.H{"message": "User deleted"})
}

Echo框架

Echo是一个高性能、可扩展的Go Web框架。

go
package main

import (
    "github.com/labstack/echo/v4"
    "net/http"
)

type User struct {
    ID       int    `json:"id"`
    Username string `json:"username"`
    Email    string `json:"email"`
}

func main() {
    e := echo.New()
    
    // 中间件
    e.Use(middleware.Logger())
    e.Use(middleware.Recover())
    
    // 路由
    e.GET("/", func(c echo.Context) error {
        return c.String(http.StatusOK, "Hello, Echo!")
    })
    
    // API路由
    api := e.Group("/api")
    api.GET("/users", getUsers)
    api.POST("/users", createUser)
    
    e.Start(":8080")
}

func getUsers(c echo.Context) error {
    users := []User{
        {ID: 1, Username: "john", Email: "[email protected]"},
    }
    return c.JSON(http.StatusOK, users)
}

func createUser(c echo.Context) error {
    user := new(User)
    if err := c.Bind(user); err != nil {
        return err
    }
    return c.JSON(http.StatusCreated, user)
}

数据库操作

GORM

GORM是Go语言最流行的ORM框架。

go
package main

import (
    "gorm.io/gorm"
    "gorm.io/driver/mysql"
    "time"
)

type User struct {
    ID        uint      `gorm:"primaryKey"`
    Username  string    `gorm:"uniqueIndex;not null"`
    Email     string    `gorm:"uniqueIndex;not null"`
    CreatedAt time.Time
    UpdatedAt time.Time
}

func main() {
    dsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
    db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err != nil {
        panic("failed to connect database")
    }
    
    // 自动迁移
    db.AutoMigrate(&User{})
    
    // 创建用户
    user := User{Username: "john", Email: "[email protected]"}
    db.Create(&user)
    
    // 查询用户
    var foundUser User
    db.First(&foundUser, "username = ?", "john")
    
    // 更新用户
    db.Model(&foundUser).Update("Email", "[email protected]")
    
    // 删除用户
    db.Delete(&foundUser, foundUser.ID)
}

原生SQL

go
package main

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
)

func main() {
    db, err := sql.Open("mysql", "user:password@/dbname")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    
    // 查询
    rows, err := db.Query("SELECT id, username, email FROM users")
    if err != nil {
        panic(err)
    }
    defer rows.Close()
    
    for rows.Next() {
        var id int
        var username, email string
        err := rows.Scan(&id, &username, &email)
        if err != nil {
            panic(err)
        }
        fmt.Printf("ID: %d, Username: %s, Email: %s\n", id, username, email)
    }
    
    // 插入
    result, err := db.Exec("INSERT INTO users(username, email) VALUES(?, ?)", "john", "[email protected]")
    if err != nil {
        panic(err)
    }
    
    lastID, err := result.LastInsertId()
    if err != nil {
        panic(err)
    }
    fmt.Printf("插入的用户ID: %d\n", lastID)
}

并发编程

Goroutine

go
package main

import (
    "fmt"
    "time"
)

func worker(id int, jobs <-chan int, results chan<- int) {
    for j := range jobs {
        fmt.Printf("worker %d processing job %d\n", id, j)
        time.Sleep(time.Second)
        results <- j * 2
    }
}

func main() {
    jobs := make(chan int, 100)
    results := make(chan int, 100)
    
    // 启动3个worker
    for w := 1; w <= 3; w++ {
        go worker(w, jobs, results)
    }
    
    // 发送9个任务
    for j := 1; j <= 9; j++ {
        jobs <- j
    }
    close(jobs)
    
    // 收集结果
    for a := 1; a <= 9; a++ {
        <-results
    }
}

Channel

go
package main

import (
    "fmt"
    "time"
)

func producer(ch chan<- int) {
    for i := 0; i < 5; i++ {
        ch <- i
        time.Sleep(time.Millisecond * 500)
    }
    close(ch)
}

func consumer(ch <-chan int) {
    for v := range ch {
        fmt.Printf("Received: %d\n", v)
    }
}

func main() {
    ch := make(chan int, 2)
    
    go producer(ch)
    go consumer(ch)
    
    time.Sleep(time.Second * 3)
}

Select语句

go
package main

import (
    "fmt"
    "time"
)

func main() {
    ch1 := make(chan string)
    ch2 := make(chan string)
    
    go func() {
        time.Sleep(time.Second)
        ch1 <- "one"
    }()
    
    go func() {
        time.Sleep(time.Second * 2)
        ch2 <- "two"
    }()
    
    for i := 0; i < 2; i++ {
        select {
        case msg1 := <-ch1:
            fmt.Println("received", msg1)
        case msg2 := <-ch2:
            fmt.Println("received", msg2)
        case <-time.After(time.Second * 3):
            fmt.Println("timeout")
        }
    }
}

错误处理

错误处理模式

go
package main

import (
    "errors"
    "fmt"
)

type User struct {
    ID       int
    Username string
    Email    string
}

type UserService struct {
    users map[int]*User
}

func NewUserService() *UserService {
    return &UserService{
        users: make(map[int]*User),
    }
}

func (s *UserService) GetUser(id int) (*User, error) {
    user, exists := s.users[id]
    if !exists {
        return nil, errors.New("user not found")
    }
    return user, nil
}

func (s *UserService) CreateUser(user *User) error {
    if user.Username == "" {
        return errors.New("username cannot be empty")
    }
    
    if user.Email == "" {
        return errors.New("email cannot be empty")
    }
    
    s.users[user.ID] = user
    return nil
}

func main() {
    service := NewUserService()
    
    // 创建用户
    user := &User{ID: 1, Username: "john", Email: "[email protected]"}
    if err := service.CreateUser(user); err != nil {
        fmt.Printf("Error creating user: %v\n", err)
        return
    }
    
    // 获取用户
    foundUser, err := service.GetUser(1)
    if err != nil {
        fmt.Printf("Error getting user: %v\n", err)
        return
    }
    
    fmt.Printf("Found user: %+v\n", foundUser)
}

测试

单元测试

go
package main

import (
    "testing"
)

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

func TestAddTable(t *testing.T) {
    tests := []struct {
        name     string
        a, b     int
        expected int
    }{
        {"positive", 1, 2, 3},
        {"negative", -1, -2, -3},
        {"zero", 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("Add(%d, %d) = %d; expected %d", tt.a, tt.b, result, tt.expected)
            }
        })
    }
}

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

HTTP测试

go
package main

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

func TestGetUsers(t *testing.T) {
    gin.SetMode(gin.TestMode)
    r := gin.New()
    r.GET("/api/users", getUsers)
    
    req, _ := http.NewRequest("GET", "/api/users", nil)
    w := httptest.NewRecorder()
    r.ServeHTTP(w, req)
    
    if w.Code != http.StatusOK {
        t.Errorf("Expected status 200, got %d", w.Code)
    }
}

部署

Docker

dockerfile
FROM golang:1.19-alpine AS builder

WORKDIR /app

COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN go build -o main .

FROM alpine:latest

WORKDIR /app

COPY --from=builder /app/main .

EXPOSE 8080

CMD ["./main"]

交叉编译

bash
# 编译Linux版本
GOOS=linux GOARCH=amd64 go build -o app-linux main.go

# 编译Windows版本
GOOS=windows GOARCH=amd64 go build -o app-windows.exe main.go

# 编译macOS版本
GOOS=darwin GOARCH=amd64 go build -o app-darwin main.go

性能优化

基准测试

go
package main

import (
    "testing"
)

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

func BenchmarkStringConcat(b *testing.B) {
    for i := 0; i < b.N; i++ {
        _ = "hello" + " " + "world"
    }
}

func BenchmarkStringBuilder(b *testing.B) {
    for i := 0; i < b.N; i++ {
        var builder strings.Builder
        builder.WriteString("hello")
        builder.WriteString(" ")
        builder.WriteString("world")
        _ = builder.String()
    }
}

内存优化

go
package main

import (
    "sync"
    "time"
)

// 对象池
var userPool = sync.Pool{
    New: func() interface{} {
        return &User{}
    },
}

func getUserFromPool() *User {
    return userPool.Get().(*User)
}

func putUserToPool(user *User) {
    user.ID = 0
    user.Username = ""
    user.Email = ""
    userPool.Put(user)
}

最佳实践

项目结构

myproject/
├── cmd/
│   └── server/
│       └── main.go
├── internal/
│   ├── handler/
│   ├── service/
│   ├── repository/
│   └── model/
├── pkg/
│   ├── database/
│   └── middleware/
├── configs/
├── scripts/
├── go.mod
└── go.sum

配置管理

go
package main

import (
    "github.com/spf13/viper"
)

type Config struct {
    Server   ServerConfig   `mapstructure:"server"`
    Database DatabaseConfig `mapstructure:"database"`
}

type ServerConfig struct {
    Port int `mapstructure:"port"`
}

type DatabaseConfig struct {
    Host     string `mapstructure:"host"`
    Port     int    `mapstructure:"port"`
    Username string `mapstructure:"username"`
    Password string `mapstructure:"password"`
    Database string `mapstructure:"database"`
}

func LoadConfig() (*Config, error) {
    viper.SetConfigName("config")
    viper.SetConfigType("yaml")
    viper.AddConfigPath(".")
    
    if err := viper.ReadInConfig(); err != nil {
        return nil, err
    }
    
    var config Config
    if err := viper.Unmarshal(&config); err != nil {
        return nil, err
    }
    
    return &config, nil
}

Go语言以其简洁的语法、强大的并发支持和优秀的性能,在微服务、云原生应用等领域得到广泛应用。