Go

Basic Types & Variables

var name string = "Go"
var age int = 18
var flag bool = true
x := 42                  // short declaration (inside functions only)
s := "hello"
f := 3.14

const Pi = 3.14159
const (
    StatusOK    = 200
    StatusError = 500
)

Functions

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

func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, fmt.Errorf("division by zero")
    }
    return a / b, nil
}

func greet(name string, greetings ...string) string {
    return fmt.Sprintf("Hello %s", name)
}

n, err := strconv.Atoi("42")
if err != nil {
    log.Fatal(err)
}

Structs & Methods

type User struct {
    ID    int
    Name  string
    Email string
}

func (u User) Display() string {
    return fmt.Sprintf("%s <%s>", u.Name, u.Email)
}

func (u *User) SetName(name string) {
    u.Name = name
}

user := User{ID: 1, Name: "Alice", Email: "a@b.com"}
user.SetName("Bob")

Pointers

x := 42
p := &x            // p is a pointer to x (*int)
fmt.Println(*p)    // dereference: prints 42
*p = 100           // modify value through pointer
fmt.Println(x)     // 100

var ptr *int       // nil pointer
if ptr != nil {
    fmt.Println(*ptr)
}

// pointer vs value in functions
func inc(n *int) {
    *n++           // modify original variable
}
inc(&x)

// new() allocates zero value and returns pointer
sp := new(string)  // *string, points to ""
fmt.Println(*sp)   // ""

// pointer to struct
user := &User{ID: 1, Name: "Alice"}
user.Name = "Bob"  // no need to dereference for struct fields
fmt.Println(user.Name)

Interfaces & Embedding

type Reader interface {
    Read(p []byte) (n int, err error)
}

type Writer interface {
    Write(p []byte) (n int, err error)
}

type ReadWriter interface {
    Reader
    Writer
}

type Animal struct {
    Name string
}

type Dog struct {
    Animal              // embedded struct
    Breed string
}

func main() {
    d := Dog{Animal: Animal{Name: "Rex"}, Breed: "Labrador"}
    fmt.Println(d.Name)   // access embedded field directly
}

Slices & Maps

// slices
nums := []int{1, 2, 3}
nums = append(nums, 4, 5)
sub := nums[1:3]
make3 := make([]int, 0, 10)

// maps
m := map[string]int{"a": 1, "b": 2}
m["c"] = 3
val, ok := m["a"]
delete(m, "b")

for k, v := range m {
    fmt.Println(k, v)
}

Concurrency

// goroutine
go func(msg string) {
    fmt.Println(msg)
}("hello")

// channels
ch := make(chan int, 3)
ch <- 42
val := <-ch

// select
select {
case msg := <-ch1:
    fmt.Println(msg)
case ch2 <- 42:
    fmt.Println("sent")
case <-time.After(time.Second):
    fmt.Println("timeout")
}

// sync.WaitGroup
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
    wg.Add(1)
    go func() {
        defer wg.Done()
        doWork()
    }()
}
wg.Wait()

Error Handling

file, err := os.Open("data.txt")
if err != nil {
    return fmt.Errorf("open file: %w", err)
}
defer file.Close()

// custom error type
type NotFoundError struct {
    Name string
}

func (e *NotFoundError) Error() string {
    return fmt.Sprintf("%s not found", e.Name)
}

// errors.Is / errors.As
if errors.Is(err, os.ErrNotExist) { }
var nfe *NotFoundError
if errors.As(err, &nfe) { }

Packages & Modules

go mod init github.com/user/project
go mod tidy
go mod vendor
go get github.com/gin-gonic/gin@latest
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
import (
    "fmt"
    "strings"
    "net/http"

    "github.com/user/project/internal/service"
)

Control Flow

// if with init statement
if err := doSomething(); err != nil {
    log.Fatal(err)
}

// switch (no break needed)
switch os := runtime.GOOS; os {
case "linux":
    fmt.Println("Linux")
case "darwin":
    fmt.Println("macOS")
default:
    fmt.Println(os)
}

// type switch
switch v := x.(type) {
case string:
    fmt.Println("string:", v)
case int:
    fmt.Println("int:", v)
}

Generics

func Map[T any, U any](s []T, f func(T) U) []U {
    result := make([]U, len(s))
    for i, v := range s {
        result[i] = f(v)
    }
    return result
}

nums := []int{1, 2, 3}
strs := Map(nums, func(n int) string {
    return strconv.Itoa(n)
})

type Number interface {
    int | int64 | float64
}

func Max[T Number](a, b T) T {
    if a > b {
        return a
    }
    return b
}

String Formatting

fmt.Sprintf("name: %s, age: %d", "Alice", 25)  // formatted string
fmt.Printf("value: %v\n", data)                 // print formatted
fmt.Fprintf(w, "status: %d", code)              // write to io.Writer

// common verbs
// %s   string
// %d   decimal integer
// %f   float (default 6 decimals), %.2f for 2 decimals
// %v   default format (any value)
// %+v  with struct field names
// %#v  Go syntax representation
// %T   type of value
// %q   quoted string
// %p   pointer address
// %02d zero-padded integer, width 2
// %x   hex encoding
// %b   binary representation
// %%   literal percent sign

fmt.Sprintf("%+v", user)          // struct with field names
fmt.Sprintf("%.2f", 3.14159)      // "3.14"
fmt.Sprintf("%04d", 7)            // "0007"
fmt.Sprintf("%x", 255)            // "ff"

Date & Time

now := time.Now()
now.Year()                         // 2025
now.Month()                        // time.April
now.Day()                          // 29
now.Hour()                         // 14
now.Weekday()                      // time.Tuesday

// formatting (reference time: Mon Jan 2 15:04:05 MST 2006)
now.Format("2006-01-02")
now.Format("2006-01-02 15:04:05")
now.Format("01/02/06")
now.Format(time.RFC3339)           // "2025-04-29T14:30:00+08:00"
now.Format(time.RFC1123)           // "Tue, 29 Apr 2025 14:30:00 UTC"

// parsing
t, _ := time.Parse("2006-01-02", "2025-04-29")
t, _ := time.Parse(time.RFC3339, "2025-04-29T14:30:00Z")

// duration
time.Sleep(2 * time.Second)
diff := time.Since(start)          // elapsed time.Duration
diff.Minutes()                     // float64
diff.Seconds()

// add / subtract
later := now.Add(24 * time.Hour)
deadline := now.AddDate(0, 1, 0)   // add 1 month

// compare
now.Before(deadline)
now.After(deadline)
now.Equal(otherTime)

Common Patterns

// context with timeout
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

// defer for cleanup
f, _ := os.Open("file.txt")
defer f.Close()

// mutex
var mu sync.Mutex
mu.Lock()
defer mu.Unlock()

// pool of goroutines
jobs := make(chan int, 100)
var wg sync.WaitGroup
for w := 0; w < 3; w++ {
    wg.Add(1)
    go func() {
        defer wg.Done()
        for j := range jobs {
            process(j)
        }
    }()
}

Testing

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

func TestDivide(t *testing.T) {
    _, err := divide(10, 0)
    if err == nil {
        t.Error("expected error for division by zero")
    }
}

// table-driven test
func TestToUpper(t *testing.T) {
    tests := []struct {
        in, want string
    }{
        {"hello", "HELLO"},
        {"Go", "GO"},
    }
    for _, tt := range tests {
        got := strings.ToUpper(tt.in)
        if got != tt.want {
            t.Errorf("ToUpper(%q) = %q, want %q", tt.in, got, tt.want)
        }
    }
}

Useful Snippets

// read entire file
data, err := os.ReadFile("config.json")

// write file
err := os.WriteFile("out.txt", []byte("hello"), 0644)

// HTTP server
http.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) {
    json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
})
log.Fatal(http.ListenAndServe(":8080", nil))

// enumerate with index
for i, v := range []string{"a", "b", "c"} {
    fmt.Println(i, v)
}

// string conversion
s := strconv.Itoa(42)
n, _ := strconv.Atoi("42")

基础类型与变量

var name string = "Go"
var age int = 18
var flag bool = true
x := 42                  // 短变量声明(仅限函数内)
s := "hello"
f := 3.14

const Pi = 3.14159
const (
    StatusOK    = 200
    StatusError = 500
)

函数

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

func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, fmt.Errorf("division by zero")
    }
    return a / b, nil
}

func greet(name string, greetings ...string) string {  // 可变参数
    return fmt.Sprintf("Hello %s", name)
}

n, err := strconv.Atoi("42")  // 多返回值
if err != nil {
    log.Fatal(err)
}

结构体与方法

type User struct {
    ID    int
    Name  string
    Email string
}

func (u User) Display() string {       // 值接收者(不修改原值)
    return fmt.Sprintf("%s <%s>", u.Name, u.Email)
}

func (u *User) SetName(name string) {  // 指针接收者(可修改原值)
    u.Name = name
}

user := User{ID: 1, Name: "Alice", Email: "a@b.com"}
user.SetName("Bob")

指针

x := 42
p := &x            // p 是指向 x 的指针 (*int)
fmt.Println(*p)    // 解引用:输出 42
*p = 100           // 通过指针修改值
fmt.Println(x)     // 100

var ptr *int       // 空指针 (nil)
if ptr != nil {
    fmt.Println(*ptr)
}

// 函数中的值与指针
func inc(n *int) {
    *n++           // 修改原始变量
}
inc(&x)

// new() 分配零值并返回指针
sp := new(string)  // *string,指向 ""
fmt.Println(*sp)   // ""

// 结构体指针
user := &User{ID: 1, Name: "Alice"}
user.Name = "Bob"  // 结构体字段无需显式解引用
fmt.Println(user.Name)

接口与嵌入

type Reader interface {
    Read(p []byte) (n int, err error)
}

type Writer interface {
    Write(p []byte) (n int, err error)
}

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

type Animal struct {
    Name string
}

type Dog struct {
    Animal              // 嵌入结构体
    Breed string
}

func main() {
    d := Dog{Animal: Animal{Name: "Rex"}, Breed: "Labrador"}
    fmt.Println(d.Name)   // 直接访问嵌入字段
}

切片与映射

// 切片 slice
nums := []int{1, 2, 3}
nums = append(nums, 4, 5)
sub := nums[1:3]                    // 切片 [2, 3]
make3 := make([]int, 0, 10)        // 预分配容量

// 映射 map
m := map[string]int{"a": 1, "b": 2}
m["c"] = 3
val, ok := m["a"]                  // 检查键是否存在
delete(m, "b")

for k, v := range m {
    fmt.Println(k, v)
}

并发编程

// goroutine 协程
go func(msg string) {
    fmt.Println(msg)
}("hello")

// channel 通道
ch := make(chan int, 3)  // 带缓冲通道
ch <- 42
val := <-ch

// select 多路复用
select {
case msg := <-ch1:
    fmt.Println(msg)
case ch2 <- 42:
    fmt.Println("sent")
case <-time.After(time.Second):
    fmt.Println("timeout")
}

// WaitGroup 等待一组协程完成
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
    wg.Add(1)
    go func() {
        defer wg.Done()
        doWork()
    }()
}
wg.Wait()

错误处理

file, err := os.Open("data.txt")
if err != nil {
    return fmt.Errorf("open file: %w", err)  // 包装错误
}
defer file.Close()

// 自定义错误类型
type NotFoundError struct {
    Name string
}

func (e *NotFoundError) Error() string {
    return fmt.Sprintf("%s not found", e.Name)
}

// errors.Is / errors.As 判断错误
if errors.Is(err, os.ErrNotExist) { }
var nfe *NotFoundError
if errors.As(err, &nfe) { }

包与模块

go mod init github.com/user/project   # 初始化模块
go mod tidy                            # 整理依赖
go mod vendor                          # 复制依赖到 vendor
go get github.com/gin-gonic/gin@latest  # 添加依赖
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
import (
    "fmt"
    "strings"
    "net/http"

    "github.com/user/project/internal/service"  // 内部包
)

控制流

// if 带初始化语句
if err := doSomething(); err != nil {
    log.Fatal(err)
}

// switch 无需 break
switch os := runtime.GOOS; os {
case "linux":
    fmt.Println("Linux")
case "darwin":
    fmt.Println("macOS")
default:
    fmt.Println(os)
}

// 类型 switch
switch v := x.(type) {
case string:
    fmt.Println("string:", v)
case int:
    fmt.Println("int:", v)
}

泛型

func Map[T any, U any](s []T, f func(T) U) []U {
    result := make([]U, len(s))
    for i, v := range s {
        result[i] = f(v)
    }
    return result
}

nums := []int{1, 2, 3}
strs := Map(nums, func(n int) string {
    return strconv.Itoa(n)
})

type Number interface {
    int | int64 | float64
}

func Max[T Number](a, b T) T {
    if a > b {
        return a
    }
    return b
}

字符串格式化

fmt.Sprintf("name: %s, age: %d", "Alice", 25)  // 格式化字符串
fmt.Printf("value: %v\n", data)                 // 格式化打印
fmt.Fprintf(w, "status: %d", code)              // 写入 io.Writer

// 常用动词
// %s   字符串
// %d   十进制整数
// %f   浮点数(默认6位小数),%.2f 保留2位
// %v   默认格式(任意值)
// %+v  显示结构体字段名
// %#v  Go 语法表示
// %T   值的类型
// %q   带引号的字符串
// %p   指针地址
// %02d 补零整数,宽度2
// %x   十六进制
// %b   二进制
// %%   百分号字面量

fmt.Sprintf("%+v", user)          // 带字段名的结构体
fmt.Sprintf("%.2f", 3.14159)      // "3.14"
fmt.Sprintf("%04d", 7)            // "0007"
fmt.Sprintf("%x", 255)            // "ff"

日期与时间

now := time.Now()
now.Year()                         // 2025
now.Month()                        // time.April
now.Day()                          // 29
now.Hour()                         // 14
now.Weekday()                      // time.Tuesday

// 格式化(参考时间: Mon Jan 2 15:04:05 MST 2006)
now.Format("2006-01-02")           // "2025-04-29"
now.Format("2006-01-02 15:04:05")  // "2025-04-29 14:30:00"
now.Format("01/02/06")             // "04/29/25"
now.Format(time.RFC3339)           // "2025-04-29T14:30:00+08:00"
now.Format(time.RFC1123)           // "Tue, 29 Apr 2025 14:30:00 UTC"

// 解析
t, _ := time.Parse("2006-01-02", "2025-04-29")
t, _ := time.Parse(time.RFC3339, "2025-04-29T14:30:00Z")

// 时间间隔
time.Sleep(2 * time.Second)
diff := time.Since(start)          // 经过的时间 time.Duration
diff.Minutes()                     // float64 分钟
diff.Seconds()                     // float64 秒

// 加减时间
later := now.Add(24 * time.Hour)
deadline := now.AddDate(0, 1, 0)   // 加 1 个月

// 比较
now.Before(deadline)               // true/false
now.After(deadline)
now.Equal(otherTime)

常用模式

// 带超时的 context
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

// defer 用于资源清理
f, _ := os.Open("file.txt")
defer f.Close()

// 互斥锁
var mu sync.Mutex
mu.Lock()
defer mu.Unlock()

// goroutine 工作池
jobs := make(chan int, 100)
var wg sync.WaitGroup
for w := 0; w < 3; w++ {
    wg.Add(1)
    go func() {
        defer wg.Done()
        for j := range jobs {
            process(j)
        }
    }()
}

测试

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

func TestDivide(t *testing.T) {
    _, err := divide(10, 0)
    if err == nil {
        t.Error("expected error for division by zero")
    }
}

// 表驱动测试
func TestToUpper(t *testing.T) {
    tests := []struct {
        in, want string
    }{
        {"hello", "HELLO"},
        {"Go", "GO"},
    }
    for _, tt := range tests {
        got := strings.ToUpper(tt.in)
        if got != tt.want {
            t.Errorf("ToUpper(%q) = %q, want %q", tt.in, got, tt.want)
        }
    }
}

实用代码片段

// 读取整个文件
data, err := os.ReadFile("config.json")

// 写入文件
err := os.WriteFile("out.txt", []byte("hello"), 0644)

// HTTP 服务
http.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) {
    json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
})
log.Fatal(http.ListenAndServe(":8080", nil))

// 遍历时获取索引
for i, v := range []string{"a", "b", "c"} {
    fmt.Println(i, v)
}

// 字符串与整数互转
s := strconv.Itoa(42)
n, _ := strconv.Atoi("42")