分享

Go 语言系列16:包

 菜籽爱编程 2022-04-27

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

main 包

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

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

// hello.go
package main

import "fmt"

func main() {
 fmt.Println("Let's go!")
}

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

创建包

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

// mymath.go
package mymath

func Add(a, b float64) float64 {
 return a + b
}


导出名字(Exported Names)

我们将 mymath 包中的函数 Add 首字母大写。在 Go 中这具有特殊意义。在 Go 中,任何以大写字母开头的变量或者函数都是被导出的名字。其它包只能访问被导出的函数和变量。在这里,我们需要在 main 包中访问 Add 函数,因此会将它们的首字母大写。

如果在 mymath.go 中将函数名从 Add 变为 add ,并且在 main.go 中调用 mymath.add 函数,则该程序编译不通过。因为如果想在包外访问一个函数,它应该首字母大写。

导入包

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

package main

import (
 "fmt"
 "mymath"
)

func main() {
 a := 10.34
 b := 20.48
 c := mymath.Add(a, b)
 fmt.Println("c =", c) // c = 30.82
}

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

import "fmt"
import "mymath"


使用别名

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

import (
    "crypto/rand"
    mrand "math/rand" // 将名称替换为 mrand 避免冲突
)

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

使用点操作

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

import . "fmt"

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

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

包的初始化

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

func init() {
}

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

包的匿名导入

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

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

import _ "fmt"

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

参考文献:

[1] Alan A. A. Donovan; Brian W. Kernighan, Go 程序设计语言, Translated by 李道兵, 高博, 庞向才, 金鑫鑫 and 林齐斌, 机械工业出版社, 2017.

👇周一至周五更新,期待你的关注👇

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多