摘要:Go语言包管理。
包使用规范
包的习惯用法:
- 包名一般是小写的,使用一个简短且有意义的名称。
- 包名一般要和所在的目录同名,也可以不同,包名中不能包含- 等特殊符号。
- 包一般使用域名作为目录名称,这样能保证包名的唯一性,比如 GitHub 项目的包一般会放到GOPATH/src/github.com/userName/projectName 目录下。
- 包名为 main 的包为应用程序的入口包,编译不包含 main 包的源码文件时不会得到可执行文件。
- 一个文件夹下的所有源码文件只能属于同一个包,同样属于同一个包的源码文件不能放在多个文件夹下。
Go 语言中,所有的定义,比如函数、变量、结构体等,如果首字母是大写,那么就可以被其他包使用;同一包下,不存在引用问题。
基于包的封装
在Go语言中封装就是把抽象出来的字段和对字段的操作封装在一起,数据被保护在内部,程序的其它包只能通过被授权的方法,才能对字段进行操作。
封装的好处: 隐藏实现细节; 可以对数据进行验证,保证数据安全合理。
封装的实现步骤:
- 将结构体、字段的首字母小写;
- 给结构体所在的包提供一个工厂模式的函数,首字母大写,类似一个构造函数;
- 提供一个首字母大写的 Set 方法(类似其它语言的 public),用于对属性判断并赋值;
- 提供一个首字母大写的 Get 方法(类似其它语言的 public),用于获取属性的值。
包的初始化
每个包都允许有一个 init 函数,当这个包被导入时,会执行该包的这个 init 函数,做一些初始化任务。 对于 init 函数的执行有两点需要注意:
- init 函数优先于 main 函数执行
- 在一个包引用链中,包的初始化是深度优先的。比如,有这样一个包引用关系:main→A→B→C,那么初始化顺序为 C.init→B.init→A.init→main
封装引用实例
建立如下工程结构,在main包中需要访问model包中的内容。
project
|---src
|---main
-main.go
|---model
-student.go
student.go
type student struct {
Name string
idCardNum string // 私有,外部包不可访问
Age int8
}
func NewStudent(stuName string, age int8) *student {
return &student{
Name: stuName,
Age: age,
}
}
// 定义结构体方法
func (stu *student) SetIdCardNum(idCN string) {
stu.idCardNum = idCN
}
// 定义结构体方法
func (stu *student) GetIdCardNum() string {
return stu.idCardNum
}
main.go
// 引入model包
import "../model"
func main() {
stu := model.NewStudent("张三",34)
stu.SetIdCardNum("42093222324234")
fmt.Println(*stu)
}
运行程序可能会遇到以下错误:
build command-line-arguments: cannot find module for xxxx
该错误与go环境变量GO111MODULE相关:
- GO111MODULE=off 无模块支持,go 会从 GOPATH 和 vendor 文件夹寻找包
- GO111MODULE=on 模块支持,go 会忽略GOPATH 和 vendor 文件夹,只根据 go.mod 下载依赖
- GO111MODULE=auto 在 $GOPATH/src 外面且根目录有 go.mod 文件时,开启模块支持
- 在使用模块的时候,GOPATH 是无意义的,不过它还是会把下载的依赖储存在 $GOPATH/src/mod 中,也会把 go install 的结果放在 $GOPATH/bin 中
设置方式:
go env -w GO111MODULE=auto
go env
在main中调用发现只能访问student结构体的Name和Age字段,idCardNum需要通过get方法获取,这样就达到包的权限控制效果。
包引用
包引用可使用相对路径和绝对路径;引用时也可以对包设置alias;还可以匿名引用。
- 包省略前缀
import (
. "fmt"
)
这个点的含义就是这个包导入之后在你调用这个包的函数时,你可以省略前缀的包名,也就是前面你调用的 fmt.Println (“hello world”) 可以省略的写成 Println (“hello world”)
- 包设置alias
import model1 "../model"
func main() {
stu := model1.NewStudent("张三", 34)
stu.SetIdCardNum("42093222324234")
}
- 包匿名引用
import _ "../model"
注意匿名引用的包并不能直接使用其中的变量和方法,不使用匿名引入的情况下,如果引入了一个未使用的包会导致编译错误,但使用匿名引入包不会导致编译错误。
import (
"database/sql"
_ "github.com/lib/pq" // enable support for Postgres
_ "github.com/go-sql-driver/mysql" // enable support for MySQL
)
db, err = sql.Open("postgres", dbname) // OK
db, err = sql.Open("mysql", dbname) // OK
db, err = sql.Open("sqlite3", dbname) // returns error: unknown driver "sqlite3"
导入一个包,只想执行包里的 init 函数,来运行一些初始化任务,此时也可以使用匿名导入。
- 绝对路径引入
基于以上工程目录结构,也可以使用绝对路径引入,绝对路径是从 $GOPATH/src 或 $GOROOT 或者 $GOPATH/pkg/mod 目录下搜索包并导入。
import "model"
注意绝对路径引入需要保证GOPATH在当前目录下,使用goland也可以设置当前工程的GOPATH。
- 相对路径引入
相对路径是从当前目录开始。
main包中引用如下:
import "../model"
参考:
https://juejin.cn/post/6844904167073382408 http://c.biancheng.net/view/91.html