非零基础自学Golang
文章目录
- 非零基础自学Golang
- 第8章 包管理
- 8.2 包的声明
- 8.3 包的导入
- 8.3.1 导入声明
- 8.3.2 远程导入
- 8.3.3 别名导入
- 8.3.4 匿名导入
第8章 包管理
8.2 包的声明
包是结构化代码的一种方式:每个程序都由包(通常简称为pkg)的概念组成,可以使用自身的包或者从其他包中导入内容。
我们先来了解一下Go语言源码的组织方式:
- Go语言的源代码以代码包为基本的组织单位。
- 在文件系统中,代码包是与文件目录一一对应的,文件目录的子目录也就是代码包的子包。
- 在工作区中,一个代码包的导入路径实际上就是从src子目录到该包的实际存储位置的相对路径。
每一个Go源文件的第一行都需要声明包的名称,声明一个包使用关键字package。
如声明一个main包:
package main
如同其他一些编程语言中的类库或命名空间的概念,每个Go文件都属于且仅属于一个包。
一个包可以由许多以“.go”为扩展名的源文件组成,因此文件名和包名一般来说都是不相同的。
代码包的名称一般会与源码文件所在的目录同名,如果不同名,在构建和安装的过程中会以代码包的名称为准。
在Go语言中,代码包中的源码文件名可以是任意的。但是,这些任意名称的源码文件都必须以包声明语句作为文件中的第一行,每个包都对应一个独立的名字空间。
包中成员以名称首字母大小写决定访问权限:
- public:首字母大写,可被包外访问。
- private:首字母小写,仅包内成员可以访问。
注意:同一个目录下不能定义不同的package。
【懂了】
8.3 包的导入
在Go语言程序中,每个包都有一个全局唯一的导入路径。
导入语句中类似““fmt””的字符串对应包的导入路径。
Go语言的规范并没有定义这些字符串的具体含义或包来自哪里,它们是由构建工具来解释的。一个导入路径代表一个目录中的一个或多个Go源文件。
8.3.1 导入声明
导入包需要使用关键字import,它会告诉编译器你想引用该位置的包中的代码,包的路径可以是相对路径,也可以是绝对路径。
// 声明方式一
import "fmt"
import "time"
// 声明方式二
import (
"fmt"
"time"
)
如上所示的标准包会在Go语言的安装位置下的src目录中找到,而其他包都需要在GOPATH环境变量中的目录下寻找,GOPATH指定的这些目录就是开发者的个人工作空间。
如果在GOPATH中仍然没有找到所需的包,编译器在编译或运行时就会报错。
8.3.2 远程导入
我们经常使用的包都是标准库中的包,也就是本地包。Go语言不仅支持我们调用本地包,还支持调用远程服务器的包,例如托管在GitHub上的一个非常热门的Web框架gin,我们就可以通过远程导入的方式将其导入使用。
import "github.com/gin-gonic/gin"
在导入之前还需要使用go get命令下载远程包:
go get github.com/gin-gonic/gin
下载时可能会报错,
go env -w GO111MODULE=on && go env -w GOPROXY=https://goproxy.cn,direct
先在 cmd 中执行下这个命令
这样就不会报错了
下面是 gin 官方提供的一个框架入门的例子:
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run() // listen and serve on 0.0.0.0:8080
}
运行结果
使用浏览器访问 接口 http://localhost:8080/ping
没问题,控制台会输出上面那种信息,表示有人请求了我们的http服务:
关于gin的这个Web框架,在后面还会重点学习
8.3.3 别名导入
在导入包时,可以指定包成员的访问方式,例如对包进行重命名,也就是使用别名的方式,避免导入两个相同包名的不同包而发生冲突。
定义包的别名只需要在导入的包名前指定别名即可。例如将fmt包取一个别名叫print:
import print "fmt"
[ 动手写 8.3.2 ]
package main
import (
print "fmt"
date "time"
)
func main() {
print.Println("当前日期为: ", date.Now().Day())
}
运行结果
【笔者现在的时间是 2022 年12 月4 日】
动手写8.3.2定义了两个别名,fmt包的别名print和time包的别名date。需要注意的是,定义了别
名后,就不能再使用该包原本的名字来调用它,只能使用它的别名来调用。
8.3.4 匿名导入
在Go语言中,如果导入了一个包而不使用,在编译时会产生“unused import”的编译错误。
有时我们可能需要导入一个包,但不会引用到这个包的标识符,在这种情况下可以使用包的匿名导入的方式,就是使用下划线“_”来重命名该包。
import _“fmt”
使用匿名导入来引入一个包,而不使用包里的函数,主要是为了调用该包中的init函数。
例如当我们想分析一个Web应用程序的性能时,导入net/http/pprof包即可,该包的init函数主要做了路由匹配,具体如下:
func init() {
http.HandleFunc("/debug/pprof/", Index)
http.HandleFunc("/debug/pprof/cmdline", Cmdline)
http.HandleFunc("/debug/pprof/profile", Profile)
http.HandleFunc("/debug/pprof/symbol", Symbol)
http.HandleFunc("/debug/pprof/trace", Trace)
}
[ 动手写 8.3.3]
package main
import (
"net/http"
_ "net/http/pprof"
)
func ping(writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("{\"message\":\"pong\"}"))
}
func main() {
http.HandleFunc("/ping", ping)
http.ListenAndServe(":8080", nil)
}
运行结果
等待请求中
动手写8.3.3实现了和动手写8.3.1一样的功能,但匿名导入了性能分析包pprof后就可以对该Web程序进行性能分析;之后浏览器访问http://localhost:8080/debug/pprof/就可以查看相关的性能参数,
还可以使用go tool pprof命令进行辅助分析。关于程序性能如何分析后面还会详细的说。
Go语言中的数据库操作也使用了相同的方法,让用户导入程序所必需的驱动,例如MySQL的驱动包github.com/go-sql-driver/mysql,使用“go get github.com/go-sql-driver/mysql”命令安装该包,
该包的init函数所做的事就是注册MySQL驱动。
func init() {
sql.Register("mysql", &MySQLDriver{})
}
当我们想要使用该驱动时就可以用匿名导入的方式导入驱动。
[ 动手写8.3.4 ]
package main
import (
"database/sql"
_ "github.com/go-sql-driver/mysql" //导入MySQL 驱动
)
func main() {
dbname := "db 连接字符串"
db, err := sql.Open("mysql", dbname) // OK
// 数据库操作
_, _ = db, err
}
运行结果
没出错 就是可以正常 启动。
动手写8.3.4导入了MySQL驱动,使得程序支持了操作MySQL的能力。