10.Go语言-包

2022-09-04 10:27:11 浏览数 (1)

第 10 章 包

包(package) 用于组织 Go 源代码,提供了更好的可重用性与可读性。Go 语言有超过 100 个的标准包,可以用 go list std | wc -l 命令查看标准包的具体数目,标准库为大多数的程序提供了必要的基础组件。

10.1 main 包

首先,我们先来看看 main 包,该包中包含一个 main() 函数,该函数是程序运行的入口。

package packagename 代码指定了某一源文件属于某一个包。它应该放在每一个源文件的第一行。例如我们 Go 的第一个程序。

代码语言:go复制
// hello go
package main

import "fmt"

func main() {
    fmt.Println("《Go语言极简一本通》")
}

package main 这一行指定该文件属于 main 包。import "fmt" 语句用于导入一个已存在的名为 fmt 的包。

10.2 创建包

下面我们创建自定义的 book 包,其中,属于某一个包的源文件都应该放置于一个单独命名的文件夹里,按照 Go 的惯例,应该用包名命名该文件夹。所以应当先创建一个 book 文件夹,位于该目录下创建一个 book.go 源文件,里面实现我们自定义的数学加法函数。请注意函数名的首字母要大写。

代码语言:go复制
// book.go
package book

func ShowBookInfo(bookName, authorName string) (string, error) {
	if bookName == "" {
		return "", errors.New("图书名称为空")
	}
	if authorName == "" {
		return "", errors.New("作者名称为空")
	}
	return bookName   ",作者:"   authorName, nil
}

Tips:

  • 导出名字(Exported Names)
    • 我们将 book 包中的函数 ShowBookInfo 首字母大写。在 Go 中这具有特殊意义。在 Go 中,任何以大写字母开头的变量或者函数都是被导出的名字。其它包只能访问被导出的函数和变量。在这里,我们需要在 main 包中访问 ShowBookInfo 函数,因此会将它们的首字母大写。
    • 如果在 book.go 中将函数名从 ShowBookInfo 变为 showBookInfo ,并且在 main.go 中调用 book.showBookInfo 函数,则该程序编译不通过。因为如果想在包外访问一个函数,它应该首字母大写。

10.3 导入包

使用包之前我们需要导入包,在 GoLand 中会帮你自动导入所需要的包。导入包的语法为 import path ,其中 path 可以是相对于工作区文件夹的相对路径,也可以是绝对路径。

代码语言:go复制
package main

import (
	"fmt"
	"book"
)

func main() {
	bookName := "《Go语言极简一本通》"
	author := "欢喜"
	bookInfo, _ := book.ShowBookInfo(bookName, author)
	fmt.Println("bookInfo = ", bookInfo)
}

导入包可以单行导入也可以多行导入,像上面的程序代码就是多行导入的例子,一般我们也建议使用多行导入,当然你也可以使用单行导入:

代码语言:go复制
import "fmt"
import "book"

10.4 使用别名

如果我们导入了两个具有同一包名的包时会产生冲突,这时我们可以为其中一个包定义别名:

代码语言:go复制
import (
    "crypto/rand"
    mrand "math/rand" // 将名称替换为 mrand 避免冲突
)

当然,我们也可以使用别名代替名字很长的包名。

10.5 使用点操作

导入一个包后,如果要使用该包中的函数,都要使用 包名.方法名 语法进行调用,对于一些使用高频的包,例如 fmt 包,每次调用打印函数时都要使用 fmt.Println() 进行调用,很不方便。我们可以在导入包的时,使用 import . package_path 语法。从此,我们打印再也不用加 fmt 了。

代码语言:go复制
import . "fmt"

func main() {
    Println("hello, world")
}

但这种用法,会有一定的隐患,就是导入的包里可能有函数,会和我们自己的函数发生冲突。

10.6 包的初始化

每个包都允许有一个或多个 init 函数, init 函数不应该有任何返回值类型和参数,在代码中也不能显式调用它,当这个包被导入时,就会执行这个包的 init 函数,做初始化任务, init 函数优先于 main 函数执行。该函数形式如下:

代码语言:go复制
func init() {
}

包的初始化顺序:首先初始化 包级别(Package Level) 的变量,紧接着调用 init 函数。包可以有多个 init 函数(在一个文件或分布于多个文件中),它们按照编译器解析它们的顺序进行调用。如果一个包导入了另一个包,会先初始化被导入的包。尽管一个包可能会被导入多次,但是它只会被初始化一次。

10.7 包的匿名导入

之前说过,导入一个没有使用的包编译会报错。但有时候我们只是想执行包里的 init 函数来执行一些初始化任务的话应该怎么办呢?

我们可以使用匿名导入的方法,使用 空白标识符(Blank Identifier)

代码语言:go复制
import _ "fmt"

由于导入时会执行该包里的 init 函数,所以编译仍会将此包编译到可执行文件中。

0 人点赞