前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >《Go小技巧&易错点100例》第二十五篇

《Go小技巧&易错点100例》第二十五篇

原创
作者头像
闫同学
发布2024-12-29 19:26:38
发布2024-12-29 19:26:38
1540
举报

本期分享

1. 使用atomic包实现无锁并发控制

2. Gin框架的中间件机制

3. 搞懂nil切片和空切片


使用atomic包实现无锁并发控制

sync/atomic包提供了原子操作,用于在多goroutine环境下安全地操作共享变量,避免使用锁带来的性能开销。

代码示例:

代码语言:go
复制
package main

import (
    "fmt"
    "sync"
    "sync/atomic"
)

var counter int64

func increment(wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 0; i < 1000; i++ {
        atomic.AddInt64(&counter, 1)
    }
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 100; i++ {
        wg.Add(1)
        go increment(&wg)
    }
    wg.Wait()
    fmt.Println("Final Counter:", counter) // 应为100 * 1000 = 100000
}

Gin框架的中间件机制

Gin是一个高性能的Go Web框架,支持中间件机制。通过自定义中间件,可以实现日志记录、认证、限流等功能,提高代码的模块化和可维护性。

代码示例:

代码语言:go
复制
package main

import (
    "github.com/gin-gonic/gin"
    "log"
    "time"
)

// 自定义日志中间件
func LoggerMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        start := time.Now()
        // 处理请求
        c.Next()
        // 请求结束后记录日志
        duration := time.Since(start)
        log.Printf("Request %s %s took %v", c.Request.Method, c.Request.URL.Path, duration)
    }
}

func main() {
    r := gin.New()
    // 使用自定义中间件
    r.Use(LoggerMiddleware())

    r.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "pong",
        })
    })

    r.Run(":8080")
}

搞懂nil切片和空切片

在Go语言中,nil切片和空切片是两个不同的概念,但它们有一些共同点和不同点。以下是它们之间的详细比较:

相同点

1)长度相同nil切片和空切片的长度都是0。这意味着它们都不包含任何元素。

2)零值:在声明切片变量但未初始化时,它的默认值是nil

不同点

1)底层指针nil切片没有底层数组,其指针部分(即数组的指针)为nil。 空切片有一个底层数组,但其长度和容量都为0,指针部分指向一个有效的零长度数组。

2)追加元素nil切片在追加元素时会分配一个新的底层数组。空切片在追加元素时,如果容量足够,可以直接在现有底层数组上进行操作,否则会分配一个新的底层数组。

3)比较nil切片与nil比较时结果为true。空切片与nil比较时结果为false

总而言之,nil切片:没有底层数组,指针为nil,长度和容量都为0。空切片:有底层数组(但长度为0),指针指向一个有效的零长度数组,长度和容量都为0。

代码示例:

代码语言:go
复制
func TestNilSlice(t *testing.T) {
	var s1 []int
	s2 := make([]int, 0)
	s3 := make([]int, 0)

	fmt.Printf("s1 pointer:%+v \ns2 pointer:%+v \ns3 pointer:%+v, \n",
		*(*reflect.SliceHeader)(unsafe.Pointer(&s1)),
		*(*reflect.SliceHeader)(unsafe.Pointer(&s2)),
		*(*reflect.SliceHeader)(unsafe.Pointer(&s3)))
	fmt.Printf("%v\n",
		(*(*reflect.SliceHeader)(unsafe.Pointer(&s1))).Data == (*(*reflect.SliceHeader)(unsafe.Pointer(&s2))).Data)
	fmt.Printf("%v\n",
		(*(*reflect.SliceHeader)(unsafe.Pointer(&s2))).Data == (*(*reflect.SliceHeader)(unsafe.Pointer(&s3))).Data)
}

输出:

代码语言:shell
复制
s1 pointer:{Data:0 Len:0 Cap:0} 
s2 pointer:{Data:1374390636216 Len:0 Cap:0} 
s3 pointer:{Data:1374390636216 Len:0 Cap:0}, 
false
true

本期结束~

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用atomic包实现无锁并发控制
  • Gin框架的中间件机制
  • 搞懂nil切片和空切片
    • 相同点
    • 不同点
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档