Go小技巧&易错点100例(二十五)

本期分享:

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

本期结束~

相关推荐
神仙别闹7 分钟前
基于C++实现的(控制台)学校开课查询系统
开发语言·c++
沐欣工作室_lvyiyi11 分钟前
基于SpringBoot的博物馆预约系统设计与实现(论文+源码)
java·spring boot·后端·计算机毕业设计
拾光记30 分钟前
Maven依赖与类加载机制
后端
只睡四小时1 小时前
JS 手写 D-pad 空间导航:电视端焦点引擎实战
android·开发语言·前端·javascript·ecmascript·hls·空间导航
2601_962218611 小时前
C++的几种编译器的实现
开发语言·c++
多弗朗皮卡丘1 小时前
C++ stack和queue
开发语言·c++·deque·queue·stack·容器适配器
维克兜率天1 小时前
【维克】弹性策略:用“乖离率“捕捉超跌反弹
android·开发语言·python·深度学习·kotlin·量化
TOOLS指南2 小时前
Chatshare 域名乱象:如何辨别仿冒站点,避坑指南
开发语言·信息可视化
迪丽热爱2 小时前
HTTP Error 500.30 - ASP.NET Core app failed to start
后端·asp.net
茉莉玫瑰花茶2 小时前
GO [ 函数 ]
开发语言·后端·golang