英文:
How does the golang package import flow work and is there a way to initialize one package multiple times within the same module?
问题
我是新手学习golang,目前正在研究包和导入的工作原理。我对这个导入有几个问题。我正在阅读这篇文章(它有超过7k个赞,所以我猜它是准确的+这是我在输入golang packages
时谷歌给我的第一个结果)。
为了解释我不理解的地方,我首先会写出项目结构和所有文件内容。
pkg
├── mypkg
| └── mypkg.go
|
├── pkg1
| └── pkg1.go
|
└── pkg2
└── pkg2.go
go.mod
main.go
如你所见,我有一个包含3个包(包括main)的模块。所有包的内容如下所示。
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
导入了pkg1
和pkg2
,而pkg1
和pkg2
都导入了mypkg
。我参考的文章中提到了以下内容(已加粗):
> 最重要的是要记住,每个导入的包只会初始化一次。
在这个前提下,我期望程序的输出如下所示:
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(某个地址)
Hello from pk2
address of prom inside mypkg is: 0xf321a3(另一个地址)
我期望按照以下步骤进行:
- 进入main包(1)
- 初始化pkg1包(2)
- 初始化mypkg包(2.1)
- 初始化mypkg中的所有全局变量 - 在我的例子中是
prom
(2.1.1) - 调用mypkg的init函数(2.1.2)
- 初始化mypkg中的所有全局变量 - 在我的例子中是
- 调用pkg1的init函数(2.2)
- 初始化mypkg包(2.1)
- 初始化pkg2包(3)
- 初始化mypkg包(3.1)
- 初始化mypkg中的所有全局变量 - 在我的例子中是
prom
(3.1.1) - 调用mypkg的init函数(3.1.2)
- 初始化mypkg中的所有全局变量 - 在我的例子中是
- 调用pkg2的init函数(3.2)
- 初始化mypkg包(3.1)
- 初始化main包(4)
- 调用main的init函数(5)
- 调用main包的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
)。
所以我的问题是:
- 文章的作者是否犯了一个错误?导入的包不是每个包只初始化一次,而是每个模块只初始化一次?
- 这是否意味着一个包中的全局变量在整个模块中始终是相同的(相同的地址),无论从哪里和多少次导入?我是说它们只会在第一次导入时初始化一次?
- 是否有办法使我的“流程”起作用?我的意思是每次导入都有独立的一个包初始化?在我的例子中,这意味着
mypkg
在pkg1
中初始化一次,在pkg2
中再初始化一次。 - 是否有关于go中包和模块的好文章,如果我读的那篇不正确的话?
我知道对于一些人来说,这些问题是关于golang的一些基础知识,但对于我这样的初学者来说,这引起了一些误解。尤其是因为程序的结果与在谷歌搜索时出现的第一篇文章的作者所写的不符。任何帮助都将不胜感激。祝一切顺利!
英文:
I'm new to golang and I'm currently researching how packages and importing them works. I have a few questions about this import. I am reading this article (it has more than 7k likes so I guess it's accurate + it's first what google gives me when I type golang packages
).
To explain what I don't understand, I will first write what the project structure looks like and what the contents of all files are.
pkg
├── mypkg
| └── mypkg.go
|
├── pkg1
| └── pkg1.go
|
└── pkg2
└── pkg2.go
go.mod
main.go
As you can see, I have module with 3 packages (4 including main). The contents of all packages are listed below.
Content of the 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()
}
Content of the 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()
}
Content of the 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)
}
Content of the 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()
}
So, main.go
includes pkg1
and pkg2
and both pkg
and pkg2
include mypkg
. The article I refer to states the following (it's bolded):
> The main thing to remember is, an imported package is initialized only once per package.
Having that in mind, I am expecting something like this to be the output of my program:
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)
My expectation is that the following steps will be followed:
- entered the main package (1)
- pkg1 package is initialized (2)
- mypkg package is initialized (2.1)
- all global variables inside mypkg is initialized -
prom
in my case (2.1.1) - init function of mypkg is called (2.1.2)
- all global variables inside mypkg is initialized -
- init function of pkg1 is called (2.2)
- mypkg package is initialized (2.1)
- pkg2 package is initialized (3)
- mypkg package is initialized (3.1)
- all global variables inside mypkg is initialized -
prom
in my case (3.1.1) - init function of mypkg is called (3.1.2)
- all global variables inside mypkg is initialized -
- init function of pkg2 is called (3.2)
- mypkg package is initialized (3.1)
- main package is initialized (4)
- init function of main is called (5)
- main function of main package is called (6)
Instead of it, I get the following output:
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
It looks like mypkg is initialized only once during the first import?! Also, the address of the global variable prom
is the same in pkg1 and pkg2 (in this case it's 0x8fe360
).
So my questions are:
- Does the author of the article made a misstake? Imported packages are not initialized only once per package, but once per module?
- Does this mean that global variables from one package will always be the same throughout the module (same address) no matter how many times and from where the package is included? I mean they will only be initialized once during first import?
- Is there some way to make my "flow" work? By that I mean there is independent initialization of one package per each import? In my example this means that
mypkg
is initialized once inpkg1
and another time inpkg2
. - Does anyone have a good article on packages and modules in go if the one I read is not correct?
I know for some these questions are some basics about golang, but for me as a beginner this caused some misunderstandings. All the more so since the result of the program's work does not match what the author of the article that comes up first during a Google search wrote. Any help is welcome. All the best!
答案1
得分: 1
程序中包含的包是一个集合,它是从main
开始的所有导入包的传递闭包。也就是说:
- 它是一个集合。每个导入的包只包含一次。这意味着,如果你在一个包中定义了一个变量,那个变量只会出现一次。
- 所有导入的包以及它们递归导入的包都包含在最终的二进制文件中。
至于初始化:你的步骤是正确的,只是mypkg
只会被初始化一次。在二进制文件中不会有多个mypkg
的副本。
英文:
The packages included in a program is a set that is the transitive closure of all imported packages starting from main
. That is:
- It is a set. Every imported package is included only once. That means, if you have a variable defined in a package, that variable only appears once.
- All imported packages, and the packages they import, recursively, are included in the final binary.
As for initialization: your steps are correct, except that mypkg
is initialized only once. There are not multiple copies of mypkg
in the binary.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论