Go 包管理方式

 

package 包的基本概念


说明:go的每一个文件都是属于一个包的,也就是说go是以包的形式来管理文件和项目目录结构的。

包的三大作用

  • 区分相同名字的函数,变量等标识符(在不同的包下面,我们文件可以写相同函数名和变量名)
  • 当程序文件很多时,可以很好的管理项目(不可能将所有文件都放在一个包里面)
  • 控制函数,变量等访问范围,即作用域

包相关说明

  • 打包语法 package util

引入包的基本语法

  • import "包的路径" 

1. 基本复⽤模块单元

以⾸字⺟⼤写来表明可被包外代码访问(函数,结构体,或者struct里面的成员都是可以被包以外的代码访问的)

2. 代码的 package 可以和所在的⽬录不⼀致

同一个目录下,源码文件的包名要保持一致

3. 同⼀⽬录⾥的 Go 代码的package 要保持⼀致

包定义


包是函数和数据的集合,将有相关特性的函数和数据放在统一的文件/目录进行管理每个包都可以作为独立的单元维护并提供给其他项目进行使用。

之前写代码都是在main包里面写代码的,如果代码写的很多了,就需要按照代码的组织功能进行拆分可以放在不同的文件里面不同的文件又可以放到不同的文件夹里面

在go里面可以认为包就是文件夹,包是函数和数据的集合。

声明


Go 源文件都需要在开头使用 package 声明所在包,包名告知编译器哪些是包的源代码用于

编译库文件,其次包名用于限制包内成员对外的可见性,最后包名用于在包外对公开成员的  

访问。main包是用来编译为二进制程序,非main包编译为库

同一个目录里面所有go文件的包名都是一致的,以后在发布包的时候就可以将单独的文件夹拷贝给别人去使用。在go里面包是可以单独进行维护的,并且提供给其他项目去使用的。

 ⚠️:在go同一个目录下面所有文件的包名必须是保持一致的,同一个包中函数是可以调用的。

可以看到可以将main里面代码分为多个文件。

如果后面还要一些其他功能可以放到新建的test文件夹下面,在定义的时候,包名和文件名一样

 

包名:

  • 满足标识符规范,小写英文字母尽量短小
  • 同一个文件夹内所有go文件的包名必须一致
  • 包名字尽量和文件夹名保持一致
  • 在调用的时候先导入包,然后使用包名去调用。

1) 介绍
Go1.11 版本提供 Go modules 机制对包进行管理,同时保留 GOPATH 和 vendor 机制,使用临
时环境变量 GO111MODULE 进行控制,GO111MODULE 有三个可选值:
a) 当 GO111MODULE 为 off 时,构建项目始终在 GOPATH 和 vendor 目录搜索目标程序依赖包
b) 当 GO111MODULE 为 on 时,构建项目则始终使用 Go modules 机制,在 GOPATH/pkg/mod
目录搜索目标程序依赖包
c) 当 GO111MODULE 为 auto(默认)时,当构建源代码不在 GOPATH/src 的子目录且包含
go.mod 文件,则使用 Go modules 机制,否则使用 GOPATH 和 vendor 机制

包管理  GOPATH


在找包的时候有标准的包,也有自定义的包,如何去找呢,在go里面是有两种方式的。一种是gopath方式,第二种就是gomode方式。

如果在其他目录下面,使用gopath进行管理,那么就需要配置环境变量gopath指向那个目录,然后在那个目录下面创建src目录,将代码放到里面进行管理。

GOPATH是一个环境变量

lulei@luleideMacBook-Pro ~ % go env GOPATH
/Users/lulei/go
lulei@luleideMacBook-Pro go % ls
bin		pkg		src

这个目录结构其实就是在gopath模式下面它的项目的一个管理方式。gopath定义了项目开发目录

  • bin 二进制文件,放二进制编译的结果
  • pkg 库文件,放库编译的结果
  • src 全部的原文件

导入包的开始是从src目录开始的,最后是包名。

code/src/math1 这个是目录
fmt.Println(math1.Add(1,2)) 包名调用

现在虽然目录结构有了,但是还需要重新设置go path为实际的路径对应上面的路径。设置为这个目录gopath/code,这个时候会去找包,会在所有的go path/src目录下面遍历,找到math1目录

可以看到在src下面创建的目录testpkg其实就是项目目录, 将所有代码都放在这个项目下面,在里面创建了math文件夹,在这个文件夹里面创建math包 ,在哪个目录下面创建包,那么包名就和文件一样。

每个文件夹下面所有的go文件的包名必须一致,在导入的时候按照大是目录,在调用的时候使用的是包名。

包名

  • main包:会编译成二进制程序,main包里的main函数是程序的入口(编译出来为可执行程序)
  • 非main包: math在go里面叫库文件,它是不直接运行的,它是给其他人提供一些功能,在调用的时候可以main包去调用也可以是非main包里面去调用。(编译出来为库文件,库文件可以认为是.a文件,.a文件链接二进制程序)

所以在整个程序的调用过程当中是从main入口的,一直会递归的调用非main的包。

上面就是gopath管理的方式。

运行:

a) 将 chapter08/gv 目录添加到 GOPATH 环境变量中
b) 编译&运行
  • 使用 go build 编译二进制文件
      命令:go build gpkgmain
      说明:编译路径 gpkgmain 下的包,main 包,则在当前目录产生以 pkgmain 命名的二进制程序
  • 使用 go run 运行二进制文件
       命令:go run gpkgmain
  • 使用 go install 编译并发布二进制文件
       命令:go install gpkgmain
       说明:编译并发布路径 gpkgmain 下的包,main 包,则在将编译后的以 pkgmain 命名的二进制程序拷贝到 bin 目录
  • 使用 go install 编译发布库文件
      命令:go install gpkgname/pkg01
      说明:编译并发布路径 gpkgname/pkg01 下的包,非 main 包,则在将编译的以包名命名的库文件拷贝到 pkg/GOOS_GOARCH 目录下
  • 使用 go install 编译发布所有二进制和库文件
       命令:go install ./…

 

GOPATH+vendor 机制


第三方包,也就是别人提供的一些包,因为都是开源的,很多开源的包和库,我们可以直接去使用。go里面使用的第三方包基本上都在github上面。

使用第三方包:先下载到本地,然后放到GOPATH/src下面

这里就会出现一个问题

公司里面开发了两个项目,都依赖testpkg/math同一个库,这个库提供了两个版本v1和v2版本。

A项目   v1版本

B项目   v2版本

这样会导致一个问题,在同一台机器上面无法编译。因为testpkg目录下只能存放一个版本。

go 1.5版本提供了vender机制,也就是在项目目录下面创建vender目录,将第三方包下载拷贝到vender目录。

那src下面和vender都有这个包,怎么找呢。

a包里面去使用了,会在a/vender目录下面去找,如果找到了就使用a目录下面的包,如果没有会去找父目录的vender目录下面找包,以此类推,最后找到GOPATH/src/vender目录,如果还没找到就去GOPATH/src下面找,还没找到去GOOPATH,GOROOT当中寻找。

a) vendor

将项目依赖包拷贝到项目下的 vendor 目录,在编译时使用项目下 vendor 目录中的包进行编译
解决问题:
  • 依赖外部包过多,在使用第三方包时需要使用 go get 进行下载
  • 第三方包在 go get 下载后不能保证开发和编译时版本的兼容性
b) 包搜索顺序,这个其实也就是优先级的问题
  • 在当前包下的 vendor 目录查找
  • 向上级目录查找,直到 GOPATH/src/vendor 目录
  • 在 GOPATH 目录查找
  • 在 GOROOT 目录查找
c) 第三方包
可以借助 go get 工具下载和安装第三方包及其依赖,需要安装与第三方包匹配的代码管理工具,比如 git、svn 等
使用方法:

常用参数:
  • -d:仅下载依赖包
  • -u:更新包并安装
  • -x:打印执行的命令
  • -v:打印构建的包
  • -insecure:允许使用 http 协议下载包
第三方包查找地址:
  • https://godoc.org
  • https://gowalker.org/

vendor其实解决的是多个项目依赖同一个路径的包但是版本不一样。

现在有来问题了,版本v1的包放在项目a的vendor目录下,版本v2的包放在项目b的vendor目录下。假设出现了v3版本的包,那么项目a和项目b会怎么做呢?

那么要将两个项目的vendor目录替换掉,但是在替换的过程当中可能会替换出一些问题来。

gomode


所以在go的 1.11版本里面,提供了gomode的机制,所以在go里面通过环境变量信息来控制是不是开启gomode,通过GO111MODULE来控制是否开启gomode,这是控制使用gopath还是使用gomode的方式。

GO111MODULE = on 就是永远使用gomode的方式,也就是必须使用这种方式。如果使用gopath方式就配置为off。

set GO111MODULE=on

还有一种是“”空,这个是默认值。也就是按照程序的结构自己去选择,如何选择的呢?有个GOPATH环境变量还一个go.mod文件,会检查当前项目不在GOPATH目录下面且当前目录有go.mod文件,这个时候使用的是gomode管理方式,否则使用GOPATH管理方式。我们设置了空值,并且代码都在GOPATH下面,所以使用GOPATH管理方式。

优势:
  • 不用设置 GOPATH,使用GOPATH要不放在一个固定的目录下面,要不得配置环境变量。使用gomode代码可任意放置
  • 自动下载依赖管理 ,版本控制  版本文件都会通过go.mod记录,所以升级只需要修改里面记录就行了。GOPROXY  在使用gomode方式的话,会使用GOPROXY 进行代理。
  • 不允许使用相对导入
  • replace 机制

使用gomode

第一步 初始化模块,一个项目就是一个模块   go mod init  项目名称  

项目名称  代码仓库路径/项目名称  其实也就是地址

在go管理包的时候,底层使用的是git/svn,如果使用了第三方包,在运行编译的时候,如果发现第三包不存在,会自动进行下载,其实这个包的名称就是其地址。

下载的包是gomode自动管理的,我们是管理不了的,咋们只需要管理自己项目的目录。gomode下载的包都在这里面。

可以看到版本都在这里面 

使用第三方包


提供第三方包

要将你的代码推送到某个地方去,如github上面去,别人就可以使用。

gomod里面写的就要是代码仓库路径+项目名称。

先去GitHub上面创建我的项目github.com/lovekeepcoding/testmath

创建gomod文件 

提供包的时候还是和项目名称保持一致。

这样就将包的代码推送到github上面去了,这样就提供了一个包,代码已经写好了,里面只提供了MathPlus函数。

提供第三方包就是定义一个gomod然后推送就行了。

包在本地是没有的,它会先去找模块 "github.com/lovekeepcoding/testmath",没有找到会去下载,这相当于依赖包会去下载到本地。(这不像之前的本地库在gomod管理的目录里面)

运行go rum mian.go 如果第三方依赖会写到gomod文件里面 可以看到依赖和版本

go run依赖的包都会自动下载,但是gopath都是手动下载。

 如果是使用第三方包

下载beego的时候还会去下载第三方依赖。可以看到别人写的第三包和你自己写的第三方包是一样的。

自己内网没有依赖第三方库,直接编译就行了

依赖内部其他团队提供的库  内部有代码管理仓库gitlab

外网的包  下载上传到自己的gitlab 然后再去引用

自己正常使用

每次创建一个文件夹就是一个项目 

testmod是模块名称,或者说是项目名称。gomod在初始化的时候一般会取一个项目名称。

这就是自己导入自己项目某一个包如何使用。 

示例:

 main.go

package main

import (
	"day1/base/package_test/utils"
	"fmt"
)

func main() {
	n := utils.Sum(1, 2)
	fmt.Println(n)
}

 utils.go

package utils

// Sum 函数名称大写 因为要被别的包引用
func Sum(a, b int) int {
	return a + b
}
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值