首頁  >  文章  >  後端開發  >  golang 套件導入流程如何運作?是否有一種方法可以在同一模組中多次初始化一個包?

golang 套件導入流程如何運作?是否有一種方法可以在同一模組中多次初始化一個包?

PHPz
PHPz轉載
2024-02-06 08:54:08941瀏覽

golang 包导入流程如何工作?是否有一种方法可以在同一模块中多次初始化一个包?

問題內容

我是 golang 新手,目前正在研究套件和導入它們的工作原理。我對這次進口有幾個問題。我正在閱讀這篇文章(它有超過 7k 個贊,所以我猜它是準確的 這是當我輸入 golang 包 時 google 給我的第一個內容)。

為了解釋我不明白的地方,我先寫一下專案結構是什麼樣的,所有文件的內容是什麼。

pkg
├── mypkg
|  └── mypkg.go
|
├── pkg1
|  └── pkg1.go
|
└── pkg2
   └── pkg2.go
go.mod
main.go

如您所見,我有包含 3 個套件的模組(4 個套件包括主套件)。下面列出了所有包的內容。

pkg1.go 的內容

package pkg1

import (
    "fmt"
    "mymod/pkg/mypkg"
)

func init() {
    fmt.println("hello everyone from pkg1 init")
}

func hellofrompkg1() {
    fmt.println("hello from pk1")
    mypkg.print()
}

pkg2.go 的內容

package pkg2

import (
    "fmt"
    "mymod/pkg/mypkg"
)

func init() {
    fmt.println("hello everyone from pkg2 init")
}

func hellofrompkg2() {
    fmt.println("hello from pk2")
    mypkg.print()
}

mypkg 的內容

package mypkg

import "fmt"

func init() {
    fmt.println("hello everyone from mypkg init")
}

var prom = 10

func print() {
    fmt.printf("address of prom inside mypkg is: %p\n", &prom)
}

main.go 的內容

package main

import (
    "fmt"
    "mymod/pkg/pkg1"
    "mymod/pkg/pkg2"
)

func init() {
    fmt.println("hello everyone from main init")
}

func main() {
    pkg1.hellofrompkg1()
    pkg2.hellofrompkg2()
}

因此,main.go 包含pkg1pkg2,並且pkg1pkg2 都包含mypkg。我引用的文章指出了以下內容(以粗體顯示):

the main thing to remember is, an imported package is initialized only once per package.

考慮到這一點,我期望我的程式的輸出是這樣的:

hello everyone from mypkg init
hello everyone from pkg1 init
hello everyone from mypkg init
hello everyone from pkg2 init
hello everyone from main init
hello from pk1
address of prom inside mypkg is: 0xfee360 (some address)
hello from pk2
address of prom inside mypkg is: 0xf321a3 (another address)

我的期望是遵循以下步驟:

  • 進入主包(1)
  • pkg1 套件已初始化 (2)
    • mypkg 套件已初始化 (2.1)
      • mypkg 中的所有全域變數都已初始化 -prom 在我的情況下 (2.1.1)
      • 呼叫 mypkg 的 init 函數(2.1.2)
    • 呼叫 pkg1 的 init 函數(2.2)
  • pkg2 套件已初始化 (3)
    • mypkg 套件已初始化 (3.1)
      • mypkg 中的所有全域變數都已初始化 -prom 在我的情況下 (3.1.1)
      • 呼叫 mypkg 的 init 函數(3.1.2)
    • 呼叫pkg2的init函數(3.2)
  • 主包初始化(4)
  • 呼叫main的init函數(5)
  • 主包的main函數被呼叫(6)

取而代之的是,我得到以下輸出:

Hello everyone from mypkg init
Hello everyone from pkg1 init
Hello everyone from pkg2 init
Hello everyone from main init
Hello from pk1
address of prom inside mypkg is: 0x8fe360
Hello from pk2
address of prom inside mypkg is: 0x8fe360

看起來 mypkg 在第一次導入期間只初始化了一次? !另外,全域變數 prom 在 pkg1 和 pkg2 中的位址是相同的(在本例中為 0x8fe360)。

所以我的問題是:

  1. 文章作者是否犯了錯?導入的包不是每個包只初始化一次,而是每個模組一次
  2. 這是否意味著一個套件中的全域變數在整個模組中始終是相同的(相同的位址),無論該套件被包含多少次以及從何處包含?我的意思是它們只會在首次導入期間初始化一次
  3. 有什麼方法可以讓我的「心流」發揮作用嗎?我的意思是每次導入都會獨立初始化一個包?在我的範例中,這表示 mypkgpkg1 中初始化一次,在 pkg2 中初始化另一次。
  4. 如果我讀的內容不正確,是否有人有一篇關於 go 中的套件和模組的好文章?

我知道對某些人來說這些問題是關於 golang 的一些基礎知識,但對於我作為初學者來說這引起了一些誤解。更重要的是,該程式的工作結果與Google搜尋中首先出現的文章的作者所寫的內容不符。歡迎任何幫助。祝一切順利!


正確答案


程式中包含的套件是一個集合,它是從 main 開始的所有導入套件的傳遞閉包。即:

  • 這是一套。每個導入的包僅包含一次。這意味著,如果您在套件中定義了一個變量,則該變數僅出現一次。
  • 所有匯入的套件以及它們遞歸導入的套件都包含在最終的二進位檔案中。

至於初始化:您的步驟是正確的,只是 mypkg 只初始化一次。二進位檔案中沒有 mypkg 的多個副本。

以上是golang 套件導入流程如何運作?是否有一種方法可以在同一模組中多次初始化一個包?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除