包的导入

导入包

import

导入单个包

import "fmt"  // 导入一个包

导入多个包(单语句,多行)

import (
	"fmt"
	"time"   // 导入多个包
)

导入多个包(单语句,单行)可读性不好,不推荐

import ("fmt";"time") // 分号隔开

导入多个包(多语句)不常用,不推荐

import "fmt"
import "time"

不能重复导入

import "fmt"
import "fmt"  // 重复导入,编译不过

包的初始化

init()

当一个包被import语句导入时,则会执行这个函数,执行顺序是按照包导入的顺序(有依赖包时先执行依赖包),源文件有多个init()函数时自上而下执行。

包别名

在程序中引用包时可以使用包的别名,设置别名之后原包名则不可用

设置别名格式如下:

import f "pkg/test"  // 设置别名为 f
f.test() // 使用别名  
.
import . "pkg/test"
test()  // 直接调用,无需使用包名
_
import _ "pkg/test"  // 不会导入包

自定义包

import "demo1/server"server目录名import "demo1/server"包名

示例:

包名与目录名一致(都为server)

package main
import "demo1/server"  //导入包 server

func main(){
    server.Test()   // 此处的server为包名,调用包server的函数Test()
}

包名与目录名不一致(包名为srv, 目录名为server)

package main
import "demo1/server" // 导入包srv

func main(){
    srv.Test()   // 此处的srv为包名,调用包srv的函数Test()
}

go语言的这个特点为包的命名提供了灵活性,但是如果包名与目录名不一致,则代码库的可理解性会很差,在不知道被导入源码的情况下很难通过import语句得知包名,程序的可读性很差。

因此包的自定义最好要遵循一下原则:
  • 一个目录下只能定义一个包(语法要求)
  • 一个包只能定义在同一个目录下(go认为不同目录下的包不是同一个包)
  • 包名和目录名相同(语法不强制,但强烈建议)

标准库中都遵循以上原则,自定义的库最好也要遵循这个原则,否则自定义库不容易使用。

包的管理

对于一个项目来说,go中的包无非有三种:

  • 标准库的包,存在与$GOROOT/src
  • 自定义库,每个项目都会有多个*.go文件组成,会形成本项目的自定义包,位于项目目录下
  • 第三方包,一般是开源的或者公司内部的工具包,它可能会被多个项目用到
包的管理

基于GOPATH的包管理

导入路径

import

go找包的顺序:

import ./module
go get

项目管理

GOPATH下一般有三个目录:

目录作用
$GOPATH/bin/go install [package] 会将可执行文件放在此处
$GOPATH/pkg/存放go build 生成的二进制对象(*.a文件等)
$GOPATH/src/存放源码。项目工程代码、第三方代码

基于此,项目工程的组织管理形式可以有多种,但必须都位于$GOPATH/src/目录下:

  1. 在$GOPATH/src/下直接放置项目工程,适用于个人的简单Demo项目
  1. 在$GOPATH/src/下通过域名组织项目,适用于开源项目。比如github上的go-cache项目,项目链接为https://github.com/patrickmn/go-cache,go get下载到本地的位置是$GOPATH/src/github.com/patrickmn/go-cache/,按照项目链接组织第三方包,方便go get自动保存包,并避免命名冲突。


3. 对于企业可以通过以下方式组织项目,企业一般在内网使用gitlab管理代码,可以按照以下方式,或者在此基础调整。

这种早期的基于GOPATH的项目管理方式有很多缺点:

  1. 项目必须放在$GOPATH/src/目录下,想在其他位置新建项目就得修改GOPATH变量,不方便。
  2. 如果不同的项目引用相同的包/模块,其中一个项目如果修改了这个模块,那么会影响其他项目。
  3. 不支持的模块的版本管理,如果不同的项目依赖了同一个模块的不同版本,切换项目时就要同时切换版本,如果依赖的模块很多,这事就比较麻烦了

基于GOPATH和vendor的包管理

为了解决单纯依赖GOPATH管理项目的问题,go v1.6版本正式支持了vendor管理机制,我们可以在项目工程目录下创建一个vendor目录,如下结构:

导入路径

有了vendor机制,包的导入路径有所变化,按照以下顺序查找:

vendorvendorsrcvendor

项目管理

项目的组织形式仍然同前述,只是在项目内部可以有自己的依赖包。但是仍然没有完全解决前述问题,因为如果两个项目中不同的依赖包又同时依赖了同一个第三方包(工程项目大了出现概率很大),则依然会出现前述问题。

基于go mod的包管理

1.11版本引入go mod,它可以彻底解决前述问题,启用go mod需要设置环境变量GO111MODULE,设置如下:

  • on 开启go mod
  • off 关闭go mod
  • auto自动,在 $GOPATH/src 外面且根目录有 go.mod 文件时,开启模块支持

导入路径

go mod init {projectName}go.mod

go.mod文件格式如下

module github/zha/test

go 1.14

require (
	github.com/patrickmn/go-cache v0.0.1 // indirect
	github.com/aaa/go-test2 v0.0.0-20220605072926-e977b358c1c3 // indirect
)

replace (
	golang.org/x/crypto => github.com/golang/crypto latest
	github.com/patrickmn/go-cache => 本地项目包的地址
) 

解释:

库名 版本号v*.*.* targetPkg => replacePkg
require项目名
go mod vendor

项目管理

go mod 支持项目工程的目录不一定要放在$GOPATH/src/ 下,放在任何地方均可;引用的第三方包则放在$GOPATH/pkg/mod/下;自定义包放在工程目录中。