Skip to content
Go back

用 Go 语言新特性简化代码

Updated:
Edit

Go 语言从 1.18 版本(泛型)开始,陆续引入了许多实用函数和方法,大幅简化了常见操作。本文挑选一些高频使用的特性,通过新旧代码对比进行说明。

1. slices 相关

1.1 查找元素

1.21 之前:

func contains(slice []int, target int) bool {
    for _, v := range slice {
        if v == target {
            return true
        }
    }
    return false
}

numbers := []int{1, 2, 3, 4, 5}
if contains(numbers, 3) {
    // ...
}

1.21 之后:

numbers := []int{1, 2, 3, 4, 5}
if slices.Contains(numbers, 3) {
    // ...
}

1.2 切片排序

1.21 之前:

numbers := []int{5, 2, 8, 1, 9}
sort.Ints(numbers)

1.21 之后:

numbers := []int{5, 2, 8, 1, 9}
slices.Sort(numbers)

1.3 切片比较

1.21 之前:

a := []int{1, 2, 3}
b := []int{1, 2, 3}

func equalSlices(a, b []int) bool {
    if len(a) != len(b) {
        return false
    }
    for i := range a {
        if a[i] != b[i] {
            return false
        }
    }
    return true
}

if equalSlices(a, b) {
    // ...
}

1.21 之后:

a := []int{1, 2, 3}
b := []int{1, 2, 3}
if slices.Equal(a, b) {
    // ...
}

1.4 遍历切片值

1.21 之前:

numbers := []int{1, 2, 3, 4, 5}
for i := 0; i < len(numbers); i++ {
    // ...
}

1.21 之后:

numbers := []int{1, 2, 3, 4, 5}
for v := range slices.Values(numbers) {
    // ...
}

1.5 反向切片遍历

1.21 之前:

numbers := []int{1, 2, 3, 4, 5}
for i := len(numbers) - 1; i >= 0; i-- {
     // ...
}

1.21 之后:

numbers := []int{1, 2, 3, 4, 5}
for _, v := range slices.Backward(numbers) {
    // ...
}

2. strings 相关

2.1 字符串裁剪

1.21 之前:

s := "  hello  "
s = strings.TrimSpace(s) // 去除字符串两端的空白字符
s = strings.Trim(s, " ") // 去除字符串两端的特定字符

1.21 之后:

s := "  hello  "
s = strings.TrimPrefix(s, " ")  // 去除特定字符前缀
s = strings.TrimSuffix(s, " ")  // 去除特定字符后缀

3. maps 相关

3.1 清空 map

1.21 之前:

m := map[string]int{"a": 1, "b": 2}
for k := range m {
    delete(m, k)
}

1.21 之后:

m := map[string]int{"a": 1, "b": 2}
maps.Clear(m)

3.2 复制 map

1.21 之前:

src := map[string]int{"a": 1, "b": 2}
dst := make(map[string]int, len(src))
for k, v := range src {
    dst[k] = v
}

1.21 之后:

src := map[string]int{"a": 1, "b": 2}
dst := maps.Clone(src)

4. time 相关

4.1 使用常量格式化日期时间

1.20 之前:

now := time.Now()
v := now.Format("2006-01-02 15:04:05")

1.20 之后:

v := now.Format(time.DateTime)

5. errors 相关

5.1 错误合并

1.20 之前:

func oldWay() error {
    var errs []string
    if err := step1(); err != nil {
        errs = append(errs, err.Error())
    }
    if err := step2(); err != nil {
        errs = append(errs, err.Error())
    }
    if len(errs) > 0 {
        return fmt.Errorf(strings.Join(errs, "; "))
    }
    return nil
}

1.20 之后:

func newWay() error {
    var errs []error
    if err := step1(); err != nil {
        errs = append(errs, fmt.Errorf("step1: %w", err))
    }
    if err := step2(); err != nil {
        errs = append(errs, fmt.Errorf("step2: %w", err))
    }
    return errors.Join(errs...)
}

5.2 错误类型断言

1.26 之前:

func handleNetworkError(err error) {
    var opErr *net.OpError
    var dnsErr *net.DNSError

    if errors.As(err, &opErr) {
        // ...
    } else if errors.As(err, &dnsErr) {
        // ...
    } else {
        // ...
    }
}

1.26 之后:

func handleNetworkError(err error) {
    if opErr, ok := errors.AsType[*net.OpError](err "*net.OpError"); ok {
        // ...
    } else if dnsErr, ok := errors.AsType[*net.DNSError](err "*net.DNSError"); ok {
        // ...
    } else {
        // ...
    }
}

6. 其他

6.1 自定义泛型三元运算函数

1.18 之后:

func Ter[T any](cond boolab T "T any"T {
  if cond {
    return a
  }
  return b
}

func main() {
  fmt.Println(Ter(true12))
  fmt.Println(Ter(false12))

6.2 随机数生成

1.22 之前:

rand.Seed(time.Now().UnixNano())
n := rand.Intn(100)

1.22 之后:

n := rand.IntN(100)

6.3 捕获循环变量

1.22 之前:

funcs := []func(){}
for i := 0; i < 3; i++ {
    i := i // 声明局部变量
    funcs = append(funcs, func() { fmt.Println(i) })
}
for _, f := range funcs {
    f() 
}

1.22 之后:

funcs := []func(){}
for i := 0; i < 3; i++ {
    funcs = append(funcs, func() { fmt.Println(i) })
}
for _, f := range funcs {
    f()
}

6.4 并发控制

1.25 之前:

var wg sync.WaitGroup
wg.Add(1)
go func() {
    defer wg.Done()
    // ...
}()
wg.Wait()

1.25 之后:

var wg sync.WaitGroup
wg.Go(func() {
    // ...
})
wg.Wait()

6.5 获取指针

1.26 之前:

// 基本类型
n := 42
p1 := &n

s := "go"
p2 := &s

// 复合类型
s := []int{111213}
p1 := &s

type Person struct{ name string }
p2 := &Person{name"alice"}

// 函数返回值
f := func() string { return "go" }
v := f()
p := &v

1.26 之后:

// 基本类型
p1 := new(42)
p2 := new("go")

// 复合类型
p1 := new([]int{111213})

type Person struct{ name string }
p2 := new(Person{name"alice"})

// 函数返回值
f := func() string { return "go" }
p := new(f())

Edit
Share this post on:

Previous Post
2025 年系统镜像对比
Next Post
2025 年 Desktop 框架对比