欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

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

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

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

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

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

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

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

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

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

copylock Analysercmd/vet中注冊,具體實(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 兩個方法
    lockerType = types.NewInterface(methods, nil).Complete()
}

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

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

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

func run(pass *analysis.Pass) (interface{}, error) {
    // ...
    // 需要檢查的節(jié)點(diǎn)
    switch node := node.(type) {
    // range語句
    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)
    // 賦值語句
    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語句
    case *ast.ReturnStmt:
        checkCopyLocksReturnStmt(pass, node)
    // ...
}

// checkCopyLocksAssign 檢查賦值操作是否復(fù)制了一個鎖
func checkCopyLocksAssign(pass *analysis.Pass, as *ast.AssignStmt) {
    for i, x := range as.Rhs {
        // 如果等號右邊的結(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會幫你運(yùn)行go vet(目前主流的VSCode和GoLand都會自動幫你運(yùn)行),你就能通過這個機(jī)制來提醒他人,盡量避免復(fù)制結(jié)構(gòu)體。

如果你的結(jié)構(gòu)體也因?yàn)槟承┰颍幌M褂谜邚?fù)制,你也可以使用該機(jī)制來警告使用者:

定義一個實(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的時候,就會得到IDE的警告信息了。

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

相關(guān)文章

  • Golang易錯知識點(diǎn)匯總

    Golang易錯知識點(diǎn)匯總

    這篇文章匯總了在開發(fā)和刷面試題過程中遇到的Golang容易搞錯的知識點(diǎn),關(guān)鍵部分也都為大家寫了代碼示例,感興趣的小伙伴可以了解一下
    2022-09-09
  • Go數(shù)組的具體使用

    Go數(shù)組的具體使用

    Go語言中的數(shù)組是一種固定長度的數(shù)據(jù)結(jié)構(gòu),它包含一組按順序排列的元素,每個元素都具有相同的類型,本文主要介紹了Go數(shù)組的具體使用,包括聲明數(shù)組、初始化數(shù)組、訪問數(shù)組元素等,感興趣的可以了解下
    2023-11-11
  • Golang?Gin解析JSON請求數(shù)據(jù)避免出現(xiàn)EOF錯誤

    Golang?Gin解析JSON請求數(shù)據(jù)避免出現(xiàn)EOF錯誤

    這篇文章主要為大家介紹了Golang?Gin?優(yōu)雅地解析JSON請求數(shù)據(jù),避免ShouldBindBodyWith出現(xiàn)EOF錯誤的源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-04-04
  • golang mapstructure庫的具體使用

    golang mapstructure庫的具體使用

    mapstructure用于將通用的map[string]interface{}解碼到對應(yīng)的 Go 結(jié)構(gòu)體中,或者執(zhí)行相反的操作,本文主要介紹了golang mapstructure庫的具體使用,感興趣的可以了解一下
    2023-09-09
  • golang?使用chromedp獲取頁面請求日志network

    golang?使用chromedp獲取頁面請求日志network

    這篇文章主要為大家介紹了golang?使用chromedp獲取頁面請求日志network方法實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Go內(nèi)置零值標(biāo)識符zero

    Go內(nèi)置零值標(biāo)識符zero

    大家學(xué)習(xí)和使用?Go?語言時,有一個神奇的概念:零值(zero-values),所以本文想給大家分享一個關(guān)于零值的新提案,目測已經(jīng)八九不離十了
    2023-08-08
  • 詳解Golang如何實(shí)現(xiàn)一個環(huán)形緩沖器

    詳解Golang如何實(shí)現(xiàn)一個環(huán)形緩沖器

    環(huán)形緩沖器(ringr?buffer)是一種用于表示一個固定尺寸、頭尾相連的緩沖區(qū)的數(shù)據(jù)結(jié)構(gòu),適合緩存數(shù)據(jù)流。本文將利用Golang實(shí)現(xiàn)一個環(huán)形緩沖器,需要的可以參考一下
    2022-09-09
  • windows下使用vscode搭建golang環(huán)境并調(diào)試的過程

    windows下使用vscode搭建golang環(huán)境并調(diào)試的過程

    這篇文章主要介紹了在windows下使用vscode搭建golang環(huán)境并進(jìn)行調(diào)試,主要包括安裝方法及環(huán)境變量配置技巧,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-09-09
  • 重學(xué)Go語言之如何使用Modules

    重學(xué)Go語言之如何使用Modules

    Go語言在Go.1.11版本發(fā)布了Go?Modules,這是一種新的Go項(xiàng)目依賴管理解決方案,可以讓Go項(xiàng)目的依賴包關(guān)系更加清晰,也更容易管理,下面就來看看Modules是如何使用的吧
    2023-07-07
  • Golang使用gvm進(jìn)行版本控制的安裝使用教程

    Golang使用gvm進(jìn)行版本控制的安裝使用教程

    這篇文章主要為大家介紹了Golang使用gvm進(jìn)行版本控制的安裝使用教程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09

最新評論