本文系第十篇Golang语言学习教程
什么是包?为什么用包?
Go语言的包和其他语言的库或模块类似,目的是为了支持封装、模块化、单独编译和代码重用。
一个包的源代码保存在一个或多个以.go
为文件后缀名的源文件中。
每个包对应一个独立的名字空间,例如,在image
包中和在unicode/utf16
包中的Decode
函数是不同的。要在外部引用该函数,需要image.Decode
形式访问。
main函数和main包
所有可执行的Go程序必须包含一个main函数,这个函数是程序的入口,main函数必须放在main包中。
在1.2,hello,world中有写过编译代码go build
和go install
两种方式,以及区别。
例1:
package main //每一个 Go 文件都应该在开头进行 package name 的声明(译注:只有可执行程序的包名应当为 main)。表明该文件属于哪个包。
import "fmt" //引入了 fmt 包,用于在 main 函数里面打印文本到标准输出。
func main() {
fmt.Println("Hello,World!")
}
//func声明函数main,调用 fmt 包的 Println 函数做标准输出。{}中的内容称之为函数体。
创建自定义的包
我们将构建一个计算矩形面积和对角线的应用程序,更好的理解包。(本例来源于Go中文网)
我们将组织代码,使得所有与矩形有关的功能都放入rectangle
包中。
创建一个自定义包rectangle
,它有一个计算矩形面积和对角线的函数。
创建一个geometry的文件夹,并在其中创建一个rectangle
文件夹,用于存放包的源文件,在这个文件夹中,所有文件都会以package rectangle
开头,因为他们属于rectangle包。
创建名为rectprops.go
的文件,编写代码
例2:
//rectprops.go
package rectangle
import "math"
func Area(len, wid float64) float64 { //定义面积的函数
area := len * wid
return area
}
func Diagonal(len, wid float64) float64 { //定义对角线的函数
diagonal := math.Sqrt((len *len) + (wid * wid)) //Sqrt函数用来计算平方根
return diagonal
}
再上面程序中,创建了两个函数用于计算Area和Diagonal。
矩形的面积= 长 * 宽
矩形的对角线= (长的平方 + 宽的平方)的平方根
math
包下面的Sqrt
函数用于计算平方根.
导入自定义包
为了使用自定义包,首先需要在可执行文件中导入包,导入的语法为 import path
。我们必须指定自定义包相对于工作区内src
文件夹的相对路径。
在geometry文件夹中创建可执行文件geometry.go用于导入自定义包。
例3
//geometry.go
package main
import (
"fmt"
"geometry/rectangle" //导入自定义包
)
func main() {
var rectLen, rectWidth float64 = 6, 7 //定义长、宽的变量
/* %.2f 会将浮点数精确到小数点后两位*/
fmt.Printf("area of rectangle %.2f\n",rectangle.Area(rectLen, rectWidth)) //调用函数计算面积
fmt.Printf("diagonal of rectangle %.2f\n",rectangle.Diagonal(rectLen,rectWidth)) //调用函数计算对角线
}
上面的代码导入了rectangle
包,并调用了里面的 Area 和 Diagonal 函数,得到矩形的面积和对角线。Printf 内的格式说明符 %.2f
会将浮点数截断到小数点两位。应用程序的输出为:
area of rectangle 42.00
diagonal of rectangle 9.22
导出名字
我们在创建函数的文件中,将两个函数名Area
和Diagonal
,首字母大写。这是因为在Go中,任何以大写字母开头的变量或函数,都是被导出的名字。其他包只能访问到被导出的函数或变量。main包要访问函数Area
和Diagonal
,因此首字母必须大写。
init函数
任何包都可以包含一个init函数,可用于执行初始化任务,也可以用于验证程序正确性。init不应有任何返回值类型和参数,init函数行书如下:
func init() {
}
包的初始化顺序如下:
- 首先初始化包级别(Package Level)的变量
- 紧接着调用 init 函数。包可以有多个 init 函数(在一个文件或分布于多个文件中),它们按照编译器解析它们的顺序进行调用。
如果一个包导入了另一个包,会先初始化被导入的包。
尽管一个包可能会被导入多次,但是它只会被初始化一次。
为了理解 init 函数,我们接下来对程序做了一些修改。
首先在 rectprops.go
文件中添加了一个 init 函数。
例4
// rectprops.go
package rectangle
import "math"
import "fmt"
func init() {
fmt.Println("rectangle package initialized")
}
func Area(len, wid float64) float64 {
area := len * wid
return area
}
func Diagonal(len, wid float64) float64 {
diagonal := math.Sqrt((len * len) + (wid * wid))
return diagonal
}
我们添加了一个 init 函数,它仅打印 rectangle package initialized
。
接下来修改main包,我们都知道矩形的长宽都应该大于0,我们将在 geometry.go
中使用 init 函数和包级别的变量来检查矩形的长和宽。
例5
//geometry.go
package main
import (
"fmt"
"geometry/rectangle"
"log"
)
/*
*1.包级别变量
*/
var rectLen, rectWidth float64 = 6, 7 //定义长、宽的变量
/*
*2.init函数检查长宽是否大于0
*/
func init() {
if rectLen <= 0 {
log.Fatal("length is less than zero")
}
if rectWidth <= 0 {
log.Fatal("width is less than zero")
}
}
func main() {
/* %.2f 会将浮点数精确到小数点后两位*/
fmt.Printf("area of rectangle %.2f\n",rectangle.Area(rectLen, rectWidth)) //调用函数计算面积
fmt.Printf("diagonal of rectangle %.2f\n",rectangle.Diagonal(rectLen,rectWidth)) //调用函数计算对角线
}
我们对 geometry.go 做了如下修改:
- 变量 rectLen 和 rectWidth 从 main 函数级别移到了包级别。
- 添加了 init 函数。当 rectLen 或 rectWidth 小于 0 时,init 函数使用 log.Fatal 函数打印一条日志,并终止了程序。
以上矩形长宽大于0 ,所以输出正常,无报错,接着我们将长修改为负数:
var rectLen, rectWidth float64 = -6, 7
运行程序将会报错:length is less than zero
空白标识符
我们在程序的开发活跃阶段,常常要导入很多包,却暂不使用它,但是运行的时候go会报错imported and not used...
,那么遇到这种情况可以使用空白标识符_
。
例6
package main
import (
"geometry/rectangle"
)
var _ = rectangle.Area // 错误屏蔽器
func main() {
}
var _ = rectangle.Area 这一行屏蔽了错误。运行时不会再报错。
以上为学习Golang 包的理解篇