模块和包
- 一个模块(module)可以视作一个项目。一个模块中所有的 Go 文件可以共用一份依赖配置,模块可以看作顶层文件夹。
- 文件夹:位于模块之下,文件夹可以有若干层级。
- .go 文件:位于文件夹之下,一个文件夹可以有若干个 .go 文件。
- 函数:位于 .go 文件之下,一个 .go 文件可以有若干个函数。函数是业务逻辑的实现主体。
模块与文件夹
模块是一个独立项目的顶层文件夹,相对于普通的文件夹,模块文件夹有一个配置文件 go.mod
。
我们可以通过 go mod init
命令来初始化一个模块。
$ go mod init hello
go: creating new go.mod: module hello
打开 go.mod
文件,可以看到内容如下:
module hello
go 1.15
分别展示了模块的名称和 Go 的版本。
若我们在 hello
文件夹下创建一个 main.go
文件,利用 beego 框架创建一个简单的 Web 服务。
package main
import "github.com/astaxie/beego"
func main() {
beego.Run()
}
在这里:
github.com/astaxie/beego
是一个第三方包,我们可以通过go get
命令来下载。
$ go get github.com/astaxie/beego
执行这个命令后,会在 go.mod
文件中添加一行:
require {
...
github.com/astaxie/beego v1.12.3
}
除了这一行之外,还会出现其他的依赖包,这些包是由 beeego 间接引入的。
同一包下不同文件中的函数调用
在同一包下的不同文件中,可以直接调用其他文件中的函数:
// /demo/main.go
package main
import "fmt"
func main() {
printHello()
}
// /demo/hello.go
package main
import "fmt"
func printHello() {
fmt.Println("Hello, World!")
}
执行 go run demo
,可以看到输出结果:
$ go run demo
Hello, World!
或者可以用 go run .
来执行当前目录下的所有文件。
注意,这里的 import "fmt"
用于导入其他包,fmt
并不是包名,而是一个相对路径,意即扫描目录下的所有代码。
不同包下的函数调用
在不同包下的文件中,需要通过 import
导入其他包,然后通过 包名.函数名
的方式调用其他包中的函数:
// demo/note/note.go
package note
import "fmt"
func PrintHello() {
fmt.Println("Hello, World!")
}
// demo/main.go
package main
import "demo/note" // 导入 note 包的所在文件夹
func main() {
note.PrintHello() // 这里的 note 是导入的包名,不一定和文件夹名一致
}
注意,包名和文件夹名可以不一致。包名最终是由 package
关键字指定的。
包的别名
在导入包时,可能会出现包名相同的情况,这时可以使用别名来区分。
// demo/main.go
import (
"fmt"
m "demo/note" // 使用 m 作为别名
)
func main() {
m.PrintHello()
}
init
函数
在 Go 语言中,每个包中都可以包含一个 init
函数,用于在包被导入时执行一些初始化操作。
// demo/note/note.go
package note
import "fmt"
func init() {
fmt.Println("note 包被导入")
}
func PrintHello() {
fmt.Println("Hello, World!")
}
// demo/main.go
import (
"fmt"
"demo/note"
)
func main() {
fmt.Println("Hello, World!")
}
执行 go run main.go
,可以看到输出结果:
note 包被导入
Hello, World!
匿名包
在导入包时,如果不需要使用包中的函数,可以使用 _
来代替包名。
// demo/main.go
import (
"fmt"
_ "demo/note" // 使用 _ 代替包名
)
func main() {
fmt.Println("Hello, World!")
}
为什么不使用函数却导入包?这是因为在导入包时,包中的 init
函数会被执行,这样可以在 init
函数中进行一些初始化操作。
为什么不直接 import "demo/note"
,而是使用 _
代替包名?这是因为 Go 语言中不允许导入包而不使用,使用 _
代替包名可以避免这个问题。