Golang模块和包的作用

模块和包的作用是合理的组织代码,组织代码包含高耦合性代码的封装,对不同来源代码的引用。封装主要通过包实现,代码引用主要通过模块来实现。

代码引用的方法包含几个方面,一是共享的代码仓库,用来存储代码,如github;二是唯一标识每个第三方代码,用来找到需要的代码;三是记录清楚使用的所有第三方代码及版本号既依赖。

Golang的模块就是解决了代码在仓库中的唯一标识,使用了哪些第三方代码及其对应的版本号。

而Golang的包实现了代码按功能划分的作用,既代码封装。

所以Golang 中代码的组织管理通过仓库,模块及包三者来完成,其中

  • 仓库(repository)就是代码仓库
  • 模块(module)是库(library)或程序(app)的根节点,存放于仓库,可包含多个包
  • 包(package)同一目录下的源码文件,编译后会归到一起

Golang包机制:

math/cmplxmath/cmplx
import "math/cmplx"
cmplx
cmplx.Inf()

非标准库的第三方包导入在样子上与标准库不同,后面会说明。

(2)同一目录下只能存在一个包;若同一目录下存在多个包,该目录被别的源文件导入时编译时会报错,不可同一路径导入两个包。

(3)目录和目录下源文件的包命名可以不同,目录被导入时只是提供包的路径;若目录名称和目录下包名称不同,当目录被导入时不必为包起别名即可在下文中使用包,当然,使用方式不是以目录名为前缀,而是以目录下的包名为前缀,不过这会导致读代码时不知道该包是来自哪个路径。所以推荐的写法是保持目录和目录下的包名称相同。

(3)不同目录下若存在相同名称的包,若在一个源文件中需同时导入使用这些包,首先一定是需要导入多个目录路径的,所以这些来自不同路径的相同名称的包就被视为了不同的包,但因为名称一样,所以同时导入到一个源文件时会导致命名冲突编译不通过:redeclared as imported package name previous declaration,因此这种情况下需要给包起别名避免冲突。因此推荐的做法是将所有包文件放在一个目录下。

publicprivate
  • 如需将某些内容设为专用内容,请以小写字母开始。
  • 如需将某些内容设为公共内容,请以大写字母开始。

如:

package calculator

var logMessage = "[LOG]"

// Version of the calculator
var Version = "1.0"

func internalSum(number int) int {
    return number - 1
}

// Sum two integer numbers
func Sum(number1, number2 int) int {
    return number1 + number2
}
logMessageVersioninternalSumSum

使用模块、包来组织代码步骤:

  1. 创建模块,使用命令 go mod init 模块名称 ,通常模块名称会使用在github上创建的仓库命名,保持唯一
go mod init github.com/myuser/myapp
go.mod

go.mod内容

module github.com/myuser/myapp

go 1.17
go get 

2. 在模块下创建包

创建包目录,在目录下创建go文件,在go文件中通过 package 包名 创建包

myapp
│  go.mod
│
├─calculator
│      sum.go
│
├─hello
│      greeting.go
│
└─main
        main.go

以上目录结构中,myapp目录为模块http://github.com/myuser/myapp的根目录,其下包含3个包calculator、hello、main,在hello包的源文件中引用sum.go

package hello

import (
        //导入格式:模块名+包路径,包路径是相对于模块位置的相对路径,模块位置及go.mod文件所在位置,通常是项目的
	//根目录
	"github.com/myuser/myapp/calculator"  
)

func Greeting(a, b int) int {
	res := calculator.Sum(a, b)  //调用格式:包名.函数
	return res
}

使用模块方式引用代码是golang推荐方式,清楚golang对引用代码的寻找方法有助于理解,排除使用import时出现的错误。golang引用代码分为三种,一是golang标准库代码,存放在 golang安装路径\+src 路径下;二是从github等代码库下载的第三方代码,存放在 GOPATH+\pkg\mod 路径下;三是自己写的本地项目代码。所以golang在寻找引用代码时也必然会在这三个位置寻找,如果在三个位置都找不到就会报错。出错率高的就是对自己项目代码的引用路径易写错。

import 	"jwtdemo/sv/pb"
package jwtdemo/sv/pb is not in GOROOT (D:\ProgramFiles\GreenProgrames\go\src\jwtdemo\sv\pb) (compile)
上面这个错误就是import引用路径不对导致,D:\ProgramFiles\GreenProgrames\go\是golang安装路径,
安装路径\+src也是标准库路径。jwtdemo\sv\pb就是import引用路径,所以可看出golang寻找路径的一种方式:
golang安装路径\src\+import路径。
如果在该路径下找不到则在项目路径下寻找,既 go.mod所在路径\+import引用路径下寻找。
jwtdemo\sv\pb 就是import引用路径。

以上是在同一模块下不同包间的引用,如果是不同模块下包文件的引用,并且要引用的模块没有上传到代码仓库github,由于你引用的是该模块的本地副本,因此需要通知 Go 不要使用远程位置。

go mod edit -replace github.com/myuser/myapp/calculator=./calculator
go mod tidy
go mod tidy

成功后go.mod文件内容更新为

module github.com/myuser/myapp

go 1.17

require github.com/myuser/myapp/calculator v0.0.0

replace github.com/myuser/myapp/calculator => ./calculator

包名冲突的解决

import
math/randcrypto/rand
import (
	crand "crypto/rand"
	"math/rand"
)

这一处理也适用于引入的包里包含与本地已经存在的名称冲突的情形。