Go语言包管理

2021/06/10

Tags: Go

摘要:Go语言包管理。


包使用规范

包的习惯用法:

Go 语言中,所有的定义,比如函数、变量、结构体等,如果首字母是大写,那么就可以被其他包使用;同一包下,不存在引用问题。

基于包的封装

在Go语言中封装就是把抽象出来的字段和对字段的操作封装在一起,数据被保护在内部,程序的其它包只能通过被授权的方法,才能对字段进行操作。

封装的好处: 隐藏实现细节; 可以对数据进行验证,保证数据安全合理。

封装的实现步骤:

  1. 将结构体、字段的首字母小写;
  2. 给结构体所在的包提供一个工厂模式的函数,首字母大写,类似一个构造函数;
  3. 提供一个首字母大写的 Set 方法(类似其它语言的 public),用于对属性判断并赋值;
  4. 提供一个首字母大写的 Get 方法(类似其它语言的 public),用于获取属性的值。

包的初始化

每个包都允许有一个 init 函数,当这个包被导入时,会执行该包的这个 init 函数,做一些初始化任务。 对于 init 函数的执行有两点需要注意:

  1. init 函数优先于 main 函数执行
  2. 在一个包引用链中,包的初始化是深度优先的。比如,有这样一个包引用关系: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相关:

设置方式:

go env -w GO111MODULE=auto
go env

在main中调用发现只能访问student结构体的Name和Age字段,idCardNum需要通过get方法获取,这样就达到包的权限控制效果。

包引用

包引用可使用相对路径和绝对路径;引用时也可以对包设置alias;还可以匿名引用。

import (
    . "fmt"
)

这个点的含义就是这个包导入之后在你调用这个包的函数时,你可以省略前缀的包名,也就是前面你调用的 fmt.Println (“hello world”) 可以省略的写成 Println (“hello world”)

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