Notes
Go
模块和包

模块和包

  • 一个模块(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 语言中不允许导入包而不使用,使用 _ 代替包名可以避免这个问题。