go有很多种方法调用依赖包,mod又加入了对包的版本管理。方式太多不免有令人迷惑和混乱的地方,希望本文能帮助大家了解目前使用规则。

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

GO111MOUDLEautoGOPATHd:/ProjectsGOPATHbinpkgsrcsrcpppGOPATH
+D:
  +/ppp
  +/Projects
    +/bin
    +/pkg
      +/mod
    +/src
      +/p1
        +/package
           +/cls1
           +/cls2
        main.go
      -/p2
%GOPATH%/src/p1/main.god:/Projects/src/p1/main.gop1github.com/c1cls1
一、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 buildgo getgo mod vendorgo mod tidy

例:

> go get github.com/c1
> go get github.com/c2
> go get bbq.org/o1
%GOPATH%/pkg/modd:/Projects/pkg/modgo mod vendorp1/vendorgo.modgo.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%GOPATH%/srcd:/Projects/src/

目录结构

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

二、包的加载方式

1.项目路径

p1

main.go 代码

import(
	"p1/package/cls1"
	"p1/package/cls2"
)
cls1cls2../../
GOPATHsrcgo.modmod

2. 相对路径

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

main.go 代码

import(
	"./package/cls1"
	"./package/cls2"
)
go build
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%/srcGOPATH

目录结构

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

3. 绝对路径

srcppp

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%/srcsrcunexpected directory layout
p1%GOPATH%/src

目录结构

+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)必须注意准确的层级关系

注意:
用了相对路径法后,层级关系就必须非常准确。

p1pckshow.go

目录结构

+D:
  +/Projects
    +/bin
    +/pkg
    +/src
  +/ppp    
    +/p1
      +/pck
        show.go
      +/package
        +/cls1
      main.go
   -/p2
pck/show.gopackage/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%/srcsrc

目录结构

+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方式”一节。

go.modgo.modgoproxygo buildgo getmodreplace [原地址] => [新地址]

A)公共和私有稍作区隔

main.go 代码

import(
	"github.com/c1"
	"github.com/c2"
	"bbq.org/o1"
	
	"p1/package/cls1"
	"p1/package/cls2"
)
%GOPATH%/srcgo.modD:/ppp/p1p1go.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 vendorp1/vendor%GOPATH%/pkg/modD:/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)系统自动调用和下载

%GOPATH%/pkg/modD:/ppp/p1/vendor%GOPATH%/pkg/modGOPATHp1/vendor

四、总结

1. 可以使用项目路径的两种情况:

%GOPATH%/srcgo.mod

2. 使用相对路径只有一种情况:

%GOPATH%/srcgo.mod

3. mod管理包的路径方式只有一种:

一旦使用mod管理包,那么只能使用项目路径,且相对路径无效,不太清楚为什么,期未来吧。

4. 公共包默认下载位置

%GOPATH%/src%GOPATH%/pkg/mod项目/vendor

5. 建议和推荐

GOPATHGOPATHgo mod tidy|vendor

文中涉及的命令解释、配置安装等内容请参考下面的文章:

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

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