一、包
包是函数和数据的集合,将具有相同特性的函数和数据进行统一的管理,每个包都可以作为独立的单元维护,并提供给其他项目使用。
1.1、声明
Go源文件都需要在开头使用 package声明所在包,包名告知编译器哪些是包的源代码用于编译库文件,其次包名用于限制包内成员对外的可见性,最后包名用于在包外对公开成员的访问。
包名使用简短的小写字母,常与所在目录名保持一致,一个包中可以由多个 Go源文件,但必须使用相同包名
package main
1.2、导入
使用import导入包,import可以每行导入1个包,也可以使用括号同时导入多个包
import "fmt"
或者
import (
"fmt"
"mypackage"
)
包的导入方式
- 绝对路径导入:在GOPATH目录查找包
- 相对路径导入:在当前文件所在目录查找
- 点导入:在调用点导入包中的成员时可以直接使用成员名称进行调用
- 别名导入:为导入的包设置别名,避免不同路径的相同包名导入会冲突
- 下划线导入:go不允许包导入却不使用,在某些情况下需要初始化包,使用下划线作为别名导入包时,包中的初始化函数(init函数)会执行
import "fmt"
import "./mypackage"
import . "fmt"
import f "fmt"
import _ "mypackage"
1.3、调用
绝对路径导入方式调用
import "fmt"
func main() {
fmt.Println("hello")
}
点导入方式调用
import . "fmt"
func main() {
Println("hello")
}
别名导入方式调用
import f "fmt"
func main() {
f.Println("hello")
}
1.4、成员可见性
Go语言使用名称首字母大小写来判断对象(常量、变量、函数、类型、结构体、方法等)的访问权限,首字母大写标识包外可见(公开的),否则仅包内可访问(内部的)
var Name string = "alex" //public
var age int = 22 //private
1.5、main与init
main包用于声明告知编译器将包编译为二进制可执行文件,在 main包中的 main函数是程序的入口,无返回值,无参数。
init函数是初始化包时使用,无返回值,无参数
二、go module机制
从1.13版本之后,go module成为Go语言默认的版本管理工具
module的优势
- 不需要设置GOPATH
- 自动下载依赖管理
- 版本控制
- 不允许使用相对导入
- replace机制
2.1、启用 go module
修改go的环境变量 GO111MODULE 以启用 go module,GO111MODULE有三个值 on,off,auto,默认值为auto;使用 go module管理依赖后会在项目根目录下生成两个文件go.mod和go.sum。
GO111MODULE="off"GOPATHvendorGO111MODULE="on"GOPATHvendorgo.modGO111MODULE="auto"$GOPATH/srcgo.mod
go env -w GO111MODULE="on"
2.2、初始化
创建一个新的项目时,先初始化
go mod init 项目名
此时,会创建一个go.mod的文件在当前项目目录,在使用 go mod tidy、go build、go test、go list命令会自动将第三方依赖包写入到go.mod文件中同时下载第三方依赖包到 GOPATH/pkg/mod/cache目录,并在当前模块目录生成一个构建状态跟踪文件 go.sum,文件中记录当前 module所有的顶层和间接依赖,以及这些依赖的校验和。
go.mod文件大致如下
module hello
go 1.16
require (
github.com/kr/fs v0.1.0 // indirect
github.com/kr/pretty v0.2.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/tools/godep v0.0.0-20180126220526-ce0bfadeb516 // indirect
golang.org/x/tools v0.1.4 // indirect
)
其中
- module定义包名
- go 1.16 是go的版本
- require 定义依赖包及版本
- indirect 表示间接引用,版本号+时间戳+哈希值
除此之外,还有replace 替换定义的依赖包及版本,以及exclude。
require "test" v0.0.0
replace "test" => "../test"
2.3、常用命令
常用的命令如下
go mod init | 初始化当前目录,在当前目录创建go.mod文件 |
go mod tidy | 根据模块的实际使用情况在go.mod文件中添加或删除 |
go mod edit | 编辑go.mod文件 |
go mod download | 下载第三方模块到本地缓存(默认在$GOPATH/pkg/mod目录) |
go mod graph | 打印所有第三方模块 |
go mod verify | 检验依赖 |
go mod why | 解释为什么需要包或模块 |
go build | 编译当前模块 |
go build ./... | 编译当前目录下所有模块 |
go list -m -json all | 显示所有模块信息 |
go list std | 显示所有标准包 |
go doc PACKAGENAME | 查看 PACKAGENAME 包的帮助信息 |
三、go module 导入包
3.1、导入同一个项目的包
在一个项目下可以定义多个包
目录结构
├── cmdb.go
├── go.mod
└── user
└── user.go
创建cmdb目录,并初始化
go mod init cmdb
user/user.go
package user
import "fmt"
func Add() {
fmt.Println("add user")
}
cmdb.go
调用user包的Add函数
package main
import (
"cmdb/user"
"fmt"
)
func main() {
fmt.Println("hello")
user.Add()
}
运行
ericdeMBP:cmdb eric$ go run .
hello
add user
3.2、导入不在同一个项目下的包
目录结构
├── cmdb
│ ├── cmdb.go
│ └── go.mod
└── user
├── go.mod
└── user.go
cmdb/cmdb.go
package main
import (
"user"
"fmt"
)
func main() {
fmt.Println("hello")
user.Add()
}
因为user包与cmdb不在同一个项目内,并且也没有发布在代码仓库中,所以如果要导入包需要使用replace
cmdb/go.mod
module cmdb
go 1.16
require "user" v0.0.0
replace "user" => "../user"
运行
ericdeMBP:cmdb eric$ go run .
hello
add user
go 标准包:https://golang.google.cn/pkg/
go 第三方包:https://pkg.go.dev/
参考文档:《手撕go语言》