最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Golang實(shí)現(xiàn)不被復(fù)制的結(jié)構(gòu)體的方法

 更新時(shí)間:2023年03月31日 16:50:50   作者:趙不貪  
sync包中的許多結(jié)構(gòu)都是不允許拷貝的,因?yàn)樗鼈冏陨泶鎯?chǔ)了一些狀態(tài)(比如等待者的數(shù)量),如果你嘗試復(fù)制這些結(jié)構(gòu)體,就會(huì)在你的?IDE中看到警告,那這是怎么實(shí)現(xiàn)的呢,下文就來(lái)和大家詳細(xì)講講

不允許復(fù)制的結(jié)構(gòu)體

sync包中的許多結(jié)構(gòu)都是不允許拷貝的,比如sync.Cond,sync.WaitGroup,sync.Pool, 以及sync包中的各種鎖,因?yàn)樗鼈冏陨泶鎯?chǔ)了一些狀態(tài)(比如等待者的數(shù)量),如果你嘗試復(fù)制這些結(jié)構(gòu)體:

var wg1 sync.WaitGroup
wg2 := wg1 // 將 wg1 復(fù)制一份,命名為 wg2
// ...

那么你將在你的 IDE 中看到一個(gè)醒目的警告:

assignment copies lock value to wg2: sync.WaitGroup contains sync.noCopy

IDE是如何實(shí)現(xiàn)這一點(diǎn)的呢?我們自己又能否利用這一機(jī)制來(lái)告訴別人,不要拷貝某個(gè)結(jié)構(gòu)體呢?

(懶得看原理,只想知道怎么用,可以直接下劃至結(jié)論部分)

實(shí)現(xiàn)原理

大部分編輯器/IDE都會(huì)在你的代碼上運(yùn)行go vet,vet是Go官方提供的靜態(tài)分析工具,我們剛剛得到的提示信息就是vet分析代碼后告訴我們的。vet的實(shí)現(xiàn)在Go源碼的cmd/vet中,里面注冊(cè)了很多不同類型的分析器,其中copylock這個(gè)分析器會(huì)檢查實(shí)現(xiàn)了LockUnlock方法的結(jié)構(gòu)體是否被復(fù)制。

copylock Analysercmd/vet中注冊(cè),具體實(shí)現(xiàn)代碼在golang.org/x/tools/go/analysis/passes/copylock/copylock.go中, 這里只摘抄部分核心代碼進(jìn)行解釋:

var lockerType *types.Interface

func init() {
    //...
    methods := []*types.Func{
        types.NewFunc(token.NoPos, nil, "Lock", nullary),
        types.NewFunc(token.NoPos, nil, "Unlock", nullary),
    }
    // Locker 結(jié)構(gòu)包括了 Lock 和 Unlock 兩個(gè)方法
    lockerType = types.NewInterface(methods, nil).Complete()
}

init函數(shù)中把包級(jí)別的全局變量lockerType進(jìn)行了初始化,lockerType內(nèi)包含了兩個(gè)方法: LockUnlock, 只有實(shí)現(xiàn)了這兩個(gè)方法的結(jié)構(gòu)體才是copylock Analyzer要處理的對(duì)象。

// lockPath 省略了參數(shù)部分,只保留了最核心的邏輯,
// 用來(lái)檢測(cè)某個(gè)類型是否實(shí)現(xiàn)了Locker接口(Lock和Unlock方法)
func lockPath(...) typePath {
    // ...
    // 如果傳進(jìn)來(lái)的指針類型實(shí)現(xiàn)了Locker接口, 就返回這個(gè)類型的信息
    if types.Implements(types.NewPointer(typ), lockerType) && !types.Implements(typ, lockerType) {
        return []string{typ.String()}
    }
    // ...
}

lockPath會(huì)檢測(cè)傳入的參數(shù)是否實(shí)現(xiàn)了LockUnlock方法,如果是則返回類型的信息。而vet會(huì)在AST上每個(gè)需要檢查的節(jié)點(diǎn)上調(diào)用lockPath函數(shù)(如賦值、函數(shù)調(diào)用等場(chǎng)景)。如果在這些會(huì)導(dǎo)致復(fù)制的場(chǎng)景中,發(fā)現(xiàn)了鎖結(jié)構(gòu)體的復(fù)制,則會(huì)報(bào)告給用戶:

func run(pass *analysis.Pass) (interface{}, error) {
    // ...
    // 需要檢查的節(jié)點(diǎn)
    switch node := node.(type) {
    // range語(yǔ)句
    case *ast.RangeStmt:
        checkCopyLocksRange(pass, node)
    // 函數(shù)聲明
    case *ast.FuncDecl:
        checkCopyLocksFunc(pass, node.Name.Name, node.Recv, node.Type)
    // 函數(shù)字面量(匿名函數(shù))
    case *ast.FuncLit:
        checkCopyLocksFunc(pass, "func", nil, node.Type)
    // 調(diào)用表達(dá)式(Foo(xxx))
    case *ast.CallExpr:
        checkCopyLocksCallExpr(pass, node)
    // 賦值語(yǔ)句
    case *ast.AssignStmt:
        checkCopyLocksAssign(pass, node)
    // 通用聲明(import/const/type/var)
    case *ast.GenDecl:
        checkCopyLocksGenDecl(pass, node)
    // 復(fù)合常量({a,b,c})
    case *ast.CompositeLit:
        checkCopyLocksCompositeLit(pass, node)
    // return語(yǔ)句
    case *ast.ReturnStmt:
        checkCopyLocksReturnStmt(pass, node)
    // ...
}

// checkCopyLocksAssign 檢查賦值操作是否復(fù)制了一個(gè)鎖
func checkCopyLocksAssign(pass *analysis.Pass, as *ast.AssignStmt) {
    for i, x := range as.Rhs {
        // 如果等號(hào)右邊的結(jié)構(gòu)體里有字段實(shí)現(xiàn)了Lock/Unlock的話,就輸出警告信息
        if path := lockPathRhs(pass, x); path != nil {
            pass.ReportRangef(x, "assignment copies lock value to %v: %v", analysisutil.Format(pass.Fset, as.Lhs[i]), path)
        }
    }
}

上面只列出了賦值操作的實(shí)現(xiàn)代碼,其它類型的檢查這里就不一一解釋了,感興趣的同學(xué)可以自行查看源碼。

結(jié)論

只要你的IDE會(huì)幫你運(yùn)行go vet(目前主流的VSCode和GoLand都會(huì)自動(dòng)幫你運(yùn)行),你就能通過(guò)這個(gè)機(jī)制來(lái)提醒他人,盡量避免復(fù)制結(jié)構(gòu)體。

如果你的結(jié)構(gòu)體也因?yàn)槟承┰?,不希望使用者?fù)制,你也可以使用該機(jī)制來(lái)警告使用者:

定義一個(gè)實(shí)現(xiàn)了LockUnlock的結(jié)構(gòu)體

type noCopy struct{}

func (*noCopy) Lock()   {}
func (*noCopy) Unlock() {}

將其放入你的結(jié)構(gòu)體中:

// Foo 代表你不希望別人復(fù)制的結(jié)構(gòu)體
type Foo struct {
    noCopy noCopy
    // ...
}

或直接讓你的結(jié)構(gòu)體實(shí)現(xiàn)LockUnlock方法:

type Foo struct {
    // ...
}

func (*Foo) Lock()   {}
func (*Foo) Unlock() {}

這樣別人在嘗試復(fù)制Foo的時(shí)候,就會(huì)得到IDE的警告信息了。

到此這篇關(guān)于Golang實(shí)現(xiàn)不被復(fù)制的結(jié)構(gòu)體的方法的文章就介紹到這了,更多相關(guān)Golang結(jié)構(gòu)體內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解Go語(yǔ)言中切片的長(zhǎng)度與容量的區(qū)別

    詳解Go語(yǔ)言中切片的長(zhǎng)度與容量的區(qū)別

    切片可以看成是數(shù)組的引用,切片的長(zhǎng)度是它所包含的元素個(gè)數(shù)。切片的容量是從它的第一個(gè)元素到其底層數(shù)組元素末尾的個(gè)數(shù)。本文將通過(guò)示例詳細(xì)講講Go語(yǔ)言中切片的長(zhǎng)度與容量的區(qū)別,需要的可以參考一下
    2022-11-11
  • Go語(yǔ)言實(shí)現(xiàn)lru淘汰策略和超時(shí)過(guò)期

    Go語(yǔ)言實(shí)現(xiàn)lru淘汰策略和超時(shí)過(guò)期

    緩存的大小是有限的,當(dāng)添加數(shù)據(jù)發(fā)現(xiàn)剩余緩存不夠時(shí),需要淘汰緩存中的部分?jǐn)?shù)據(jù),本文主要介紹了Go語(yǔ)言實(shí)現(xiàn)lru淘汰策略和超時(shí)過(guò)期,感興趣的可以了解一下
    2024-02-02
  • 淺談Go語(yǔ)言中字符串和數(shù)組

    淺談Go語(yǔ)言中字符串和數(shù)組

    這篇文章主要簡(jiǎn)單介紹了Go語(yǔ)言中字符串和數(shù)組的使用方法和申明方式,需要的朋友可以參考下
    2015-01-01
  • 利用go語(yǔ)言判斷是否是完全二叉樹(shù)

    利用go語(yǔ)言判斷是否是完全二叉樹(shù)

    這篇文章主要介紹了利用go語(yǔ)言判斷是否是完全二叉樹(shù),當(dāng)一個(gè)節(jié)點(diǎn)存在右子節(jié)點(diǎn)但是不存在左子節(jié)點(diǎn)這顆樹(shù)視為非完全二叉樹(shù),通過(guò)利用GO語(yǔ)言判斷來(lái)判斷出否是完全二叉樹(shù),詳細(xì)內(nèi)容參考如下
    2022-05-05
  • Golang實(shí)現(xiàn)內(nèi)網(wǎng)穿透詳解

    Golang實(shí)現(xiàn)內(nèi)網(wǎng)穿透詳解

    這篇文章主要為大家詳細(xì)介紹了Golang實(shí)現(xiàn)內(nèi)網(wǎng)穿透的相關(guān)知識(shí),包括原理和代碼實(shí)現(xiàn),文中的示例代碼講解詳細(xì),有需要的小伙伴可以參考一下
    2024-11-11
  • 使用Golang如何實(shí)現(xiàn)簡(jiǎn)易的令牌桶算法

    使用Golang如何實(shí)現(xiàn)簡(jiǎn)易的令牌桶算法

    這篇文章主要介紹了使用Golang如何實(shí)現(xiàn)簡(jiǎn)易的令牌桶算法問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • 深入理解golang的異常處理機(jī)制

    深入理解golang的異常處理機(jī)制

    Go語(yǔ)言追求簡(jiǎn)潔優(yōu)雅,所以,Go語(yǔ)言不支持傳統(tǒng)的 try…catch…finally 這種異常,下面這篇文章主要給大家介紹了關(guān)于golang的異常處理機(jī)制,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-07-07
  • Go語(yǔ)言操作數(shù)據(jù)庫(kù)及其常規(guī)操作的示例代碼

    Go語(yǔ)言操作數(shù)據(jù)庫(kù)及其常規(guī)操作的示例代碼

    這篇文章主要介紹了Go語(yǔ)言操作數(shù)據(jù)庫(kù)及其常規(guī)操作的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • 如何解析golang中Context在HTTP服務(wù)中的角色

    如何解析golang中Context在HTTP服務(wù)中的角色

    這篇文章主要介紹了如何解析golang中Context在HTTP服務(wù)中的角色問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • Go語(yǔ)言中普通函數(shù)與方法的區(qū)別分析

    Go語(yǔ)言中普通函數(shù)與方法的區(qū)別分析

    這篇文章主要介紹了Go語(yǔ)言中普通函數(shù)與方法的區(qū)別,以實(shí)例形式對(duì)比分析了普通函數(shù)與方法使用時(shí)的區(qū)別與相關(guān)技巧,需要的朋友可以參考下
    2015-02-02

最新評(píng)論

柯坪县| 镇安县| 仁化县| 巴林右旗| 合水县| 齐河县| 汝南县| 德昌县| 策勒县| 商洛市| 南岸区| 邛崃市| 彭泽县| 紫阳县| 赤水市| 廉江市| 郧西县| 盘山县| 汽车| 高邮市| 襄汾县| 白沙| 永吉县| 会理县| 察哈| 万山特区| 介休市| 兴安盟| 唐山市| 夏河县| 石泉县| 余姚市| 策勒县| 叶城县| 雷山县| 元谋县| 宣威市| 北宁市| 安阳县| 荔波县| 营山县|