0
点赞
收藏
分享

微信扫一扫

Golang学习日志 ━━ 理解依赖包的管理(mod/非mod)和加载方式(项目路径、相对路径、绝对路径)及实战运用

guanguans 2022-03-14 阅读 12

目录结构

+D:
  +/Projects
    +/bin
    +/pkg
      +/mod
    +/src
      +/p1
        +/package
           +/cls1
           +/cls2
        main.go
      -/p2

本文所用案例的环境设定:

  1. GO111MOUDLEauto
  2. GOPATHd:/Projects
  3. GOPATH下目录有binpkgsrc
  4. src中以不同目录区分项目,
  5. 本文所提到的共享包指的是类似github.com/c1类型的依赖包;而私有包则是指cls1类型的依赖包

下面的操作都是以 d:/Projects/src/p1/main.go 为例进行,即名称为p1的项目,。

一、mod / 非mod 管理方式

go提供了两种项目依赖包的管理方式,一种是mod方式,一种是非mod方式。

1. mod方式

main.go 代码

import(
	"github.com/c1"
	"github.com/c2"
	"bbq.org/o1"
)

终端执行

> go mod init

此刻系统自动生成go.mod,用于标记所有依赖包。

如果go.mod内容为空或者go build时提示依赖包不存在,那可能因为依赖包下载失败了,此刻就需要使用合适的代理,再用go buildgo get命令获取代码包:

> go get github.com/c1
> go get github.com/c2
> go get bbq.org/o1

go会将这些包下载到%GOPATH%/pkg/mod(本例即d:/Projects/pkg/mod)目录中,并将这些包标记在go.mod内,同时生成go.sum文件,用于记录包版本。
go.mod内容如下:

module p1

go 1.17

require (
	github.com/c1 v0.0.0-20190825152654-46b345b51c96 // indirect
	github.com/c2 v0.3.1 // indirect
	bbq.org/o1 v1.24.0 // indirect
)

下载后go会根据版本号自动区分目录

目录结构

+D:
  +/Projects
    +/bin
    +/pkg
      +/mod
        +/github.com
          +/c1@v0.0.0-20190825152654-46b345b51c96
          +/c2@v0.3.1
        +/bbq.org
          +/o1@v1.24.0
    +/src
      +/p1
        +/package
           +/cls1
           +/cls2
        main.go
        go.mod
        go.sum
      -/p2

2.非mod方式

加载方式有多种,此处的例子就是下一节提到的"项目路径"方式。

main.go 代码

import(
	"github.com/c1"
	"github.com/c2"
	"bbq.org/o1"
)

github.com/c1github.com/c2bbq.org/o1三个目录移到d:/Projects/src/下即可。
注意这种非mod方式目录是不能带版本号的,所以一般不适用于共享依赖包

目录结构

+D:
  +/Projects
    +/bin
    +/pkg
    +/src
      +/github.com
        +/c1
        +/c2
      +/bbq.org
        +/o1
      +/p1
        +/package
          +/cls1
          +/cls2
        main.go
     -/p2

二、包的加载方式

1.项目路径

以项目名为开头直接引用,我称为项目路径

main.go 代码

import(
	"p1/package/cls1"
	"p1/package/cls2"
)
  1. 依托环境变量GOPATH,其src下的项目可直接使用本载入方式;
  2. 项目中有go.mod文件,即该项目使用了mod方式管理包,那么也使用本载入方式。

2. 相对路径

在go没有mod的早期版本,本方式较为常见。

main.go 代码

import(
	"./package/cls1"
	"./package/cls2"
)

系统提示目录结构不合理

unexpected directory layout:
	import path: _/D_/Projects/src/p1/package
	root: D:\Projects\src
	dir: D:\Projects\src\p1\pkg
	expand root: D:\Projects
	expand dir: D:\Projects\src\p1\pkg
	separator: \

警告你引用的包怎么能和项目都在src下面,不合适,赶紧换~~~
改动很简单,把项目p1移出%GOPATH%/src目录就好了,让GOPATH里只放系统级或共享级的内容。

目录结构

+D:
  +Projects
    +bin
    +pkg
    +src
  +ppp    
    +p1
      +package
        +cls1
        +cls2
      main.go
   -p2

go build 报错 unexpected directory layout 的解决

3. 绝对路径

从没用过,为了写本文试了一下,发现不行,无论项目在src目录内还是ppp目录内,都提示不存在

main.go 代码

import(
	"d:/Projects/src/p1/package/cls1"
	"d:/Projects/src/p1/package/cls2"
)

系统提示路径无效

main.go:3:2: invalid import path: "d:/Projects/src/p1/package/cls1"
main.go:4:2: invalid import path: "d:/Projects/src/p1/package/cls2"

三、综合使用

结合上面的测试,实践中可以用三种方法。

1. 相对路径法

A)共享和私有稍作区隔

main.go 代码

import(
	"github.com/c1"
	"github.com/c2"
	"bbq.org/o1"
	
	"./package/cls1"
	"./package/cls2"
)

采用相对路径的项目,其目录不能放在%GOPATH%/src目录下,请移到别处,src目录主要用来放依赖包,否则会提示unexpected directory layout错误

目录结构

+D:
  +/Projects
    +/bin
    +/pkg
    +/src
      +/github.com
        +/c1
        +/c2
      +/bbq.org
        +/o1
  +/ppp    
    +/p1
      +/package
        +/cls1
        +/cls2
      main.go
   -/p2

B)共享和私有都属一个项目

main.go 代码

import(
	"./package/github.com/c1"
	"./package/github.com/c2"
	"./package/bbq.org/o1"
	
	"./package/cls1"
	"./package/cls2"
)

用这个方法,那就和GOPATH完全没关系了,如果要让兄弟帮忙,把整个项目包给他就完事了,轻松。

目录结构

+D:
  +/Projects
    +/bin
    +/pkg
    +/src
  +/ppp    
    +/p1
      +/package
        +/cls1
        +/cls2
        +/github.com
          +/c1
          +/c2
        +/bbq.org
          +/o1
      main.go
   -/p2

C)必须注意准确的层级关系

比如p1下多一个pck目录

目录结构

+D:
  +/Projects
    +/bin
    +/pkg
    +/src
  +/ppp    
    +/p1
      +/pck
        show.go
      +/package
        +/cls1
      main.go
   -/p2

如果pck/show.go内调用package/cls1,就需要这么写了

show.go 代码

import(
	"../package/cls1"
)

2. 非mod + 项目路径法

参考本文的“非mod方式

A)共享和私有稍作区隔

main.go 代码

import(
	"github.com/c1"
	"github.com/c2"
	"bbq.org/o1"
	
	"p1/package/cls1"
	"p1/package/cls2"
)

将共享包和项目同级,都放在%GOPATH%/src目录中,共享包相当于一个个项目,go会自动去src下找项目调用。
总之无论嵌套多少层,一律从项目名开始写包路径

目录结构

+D:
  +/Projects
    +/bin
    +/pkg
    +/src
      +/github.com
        +/c1
        +/c2
      +/bbq.org
        +/o1
      +/p1
        +/package
          +/cls1
          +/cls2
        main.go
     -/p2

B)共享和私有都属一个项目

main.go 代码

import(
	"p1/package/github.com/c1"
	"p1/package/github.com/c2"
	"p1/package/bbq.org/o1"
	
	"p1/package/cls1"
	"p1/package/cls2"
)

意思是一样的:一切从项目名开始,但是这里公私都打包在一个package里了,知道了原理,怎么玩就是你自己的事情了。

目录结构

+D:
  +/Projects
    +/bin
    +/pkg
    +/src
      +/p1
        +/package
          +/cls1
          +/cls2
          +/github.com
            +/c1
            +/c2
          +/bbq.org
            +/o1
        main.go
     -/p2

3. mod + 项目路径法

mod初始化的方法请参考本文的“mod方式”一节。

A)共享和私有稍作区隔

main.go 代码

import(
	"github.com/c1"
	"github.com/c2"
	"bbq.org/o1"
	
	"p1/package/cls1"
	"p1/package/cls2"
)

并非只有当项目处于%GOPATH%/src下才能使用“项目路径”法。
随便搞个文件夹,只要go.mod所在目录名就是项目名~~
比如这里的D:/ppp/p1p1就是项目名,因为go.modp1文件夹内。

目录结构

+D:
  +/Projects
    +/bin
    +/pkg
      +/mod
        +/github.com
          +/c1@v0.0.0-20190825152654-46b345b51c96
          +/c2@v0.3.1
        +/bbq.org
          +/o1@v1.24.0
    +/src
  +/ppp    
    +/p1
      +/package
        +/cls1
        +/cls2
      main.go
      go.mod
      go.sum
   -/p2

B)共享和私有都属一个项目

main.go 代码

import(
	"github.com/c1"
	"github.com/c2"
	"bbq.org/o1"
	
	"p1/package/cls1"
	"p1/package/cls2"
)

代码部分并未改变,但是目录结构变了:
通过go mod vendor命令将依赖包下载到p1/vendor目录中。
(上一个例子中的依赖包在%GOPATH%/pkg/mod,即D:/Project/pkg/mod目录中)

终端执行

> go mod vendor

这时系统会在项目内生成一个vendor目录,并且将所有包都放入这个目录中。

目录结构

+D:
  +/Projects
    +/bin
    +/pkg
    +/src
  +/ppp    
    +/p1
      +/package
        +/cls1
        +/cls2
      +/vendor      
        +/github.com
          +/c1@v0.0.0-20190825152654-46b345b51c96
          +/c2@v0.3.1
        +/bbq.org
          +/o1@v1.24.0
      main.go
      go.mod
      go.sum
   -/p2

C)系统自动调用和下载

  • 在mod方式下,系统会到D:/Project/pkg/mod目录和D:/ppp/p1/vendor目录读取依赖包。
  • 如果两个目录都没有,则会将包下载到D:/Project/pkg/mod目录中,毕竟GOPATH放在那里不能当摆设啊~~
  • 如果两个目录都有,则会优先加载。。。。(估计是vendor,但还没测试过,有知道的朋友可以留言)

参考:
《go modules:使用 mod 管理项目依赖包,通过vendor实现一键分发编译包》
《Go:go mod vendor 使用》
《go package、import、go.mod 理解 以及 私有包引入》
《go-module的使用》
《go安装依赖包(go get, go module)》
《Golang学习日志 ━━ 下载及安装》
《Golang学习日志 ━━ LiteIDE的主要配置》
《Golang学习日志 ━━ VSCode安装Go插件(代理的使用)及初用mod》

如果有写的不对的地方,欢迎指正,谢谢。

举报

相关推荐

0 条评论