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 之前):

// 比较两个切片是否相等
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
}

新版本(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++ {
    fmt.Println(numbers[i])
}

新版本(1.21 之后):

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

1.5 反向切片遍历

旧版本(1.21 之前):

// 反向遍历切片
numbers := []int{1, 2, 3, 4, 5}
for i := len(numbers) - 1; i >= 0; i-- {
    fmt.Println(numbers[i])
}

新版本(1.21 之后):

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

2. strings 包增强

2.1 字符串裁剪

旧版本(1.21 之前):

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

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

新版本(1.21 之后):

s := "  hello  "
s = strings.TrimSpace(s)  // 和之前功能一样
s = strings.TrimPrefix(s, " ")  // 只去除前缀
s = strings.TrimSuffix(s, " ")  // 只去除后缀

2.2 字符串分割

旧版本(1.21 之前):

// 分割字符串
parts := strings.Split("a,b,c", ",")
// 需要手动处理空字符串
if parts[0] == "" {
    parts = parts[1:]
}

新版本(1.21 之后):

// 新增了更多分割选项
parts := strings.Split("a,b,c", ",")
// 自动过滤空字符串
parts = strings.Split("a,,b,c", ",")  // ["a", "", "b", "c"]
parts = strings.SplitAfter("a,b,c", ",")  // ["a,", "b,", "c"]

3. maps 包增强

3.1 清空 map

旧版本(1.21 之前):

// 清空 map
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 之前):

// 复制 map
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 时区转换

旧版本:

now := time.Now()
loc, _ := time.LoadLocation("Asia/Shanghai")
now = now.In(loc)

新版本:

now := time.Now().Local()

4.2 格式化为数据库时间

旧版本(1.20 之前):

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

新版本(1.20 之后):

now := time.Now()
v := now.Format(time.DateTime)
println(v)

5. 其他新特性

5.1 错误处理

旧版本:

// 处理多个错误
var err1, err2 error
if err1 != nil {
    return fmt.Errorf("error 1: %v", err1)
}
if err2 != nil {
    return fmt.Errorf("error 2: %v", err2)
}

新版本:

// 使用 errors.Join 合并多个错误
err := errors.Join(err1, err2)
if err != nil {
    return err
}

5.2 随机数生成

旧版本:

// 生成随机整数
rand.Seed(time.Now().UnixNano())
n := rand.Intn(100)

新版本:

// 更高效的随机数生成
n := rand.IntN(100)  // 无需显式设置种子

5.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()
}

5.4 并发控制

旧版本(1.25 之前):

var wg sync.WaitGroup
wg.Add(1)
go func() {
    defer wg.Done()
    fmt.Println("go is awesome")
}()
wg.Wait()

新版本(1.25 之后):

var wg sync.WaitGroup
wg.Go(func() {
    fmt.Println("go is awesome")
})
wg.Wait()

Edit
Share this post on:

Next Post
JProfiler 激活码