3 包与作用域

[TOC]

包与作用域

Go使用包组织源码结构,任何源码必须属于某个包,源码中第一行使用package packageName 定义源码所在包。

  • Go并不强制要求包名和所在目录相同,但一般包的源码文件在包名目录下。

  • 包的定义不包括目录路径,引用时是全路径引用。

  • 包名一般是使用一个小写的简短的命名。

  • 通过包名实现命名空间的功能,不同包下标识符在别的包导入通过"包名.标识符"调用,不同包之间的标识符互不干扰。

包引用

  • 标准包的源码位于$GOROOT/src下,自定义包和第三方包的源码必须在$GOPATH/src下才能被引用。

包引用路径

  • 全路径引用和相对路径引用。

全路径引用

  • 包的绝对路径是$GOROOT/src或$GOPATH/src后的源码的全路径

  • 如 import "database/sql"

包引用格式

标准引用方式,使用最后的包名调用

  • import "fmt"

  • 调用 fmt.Println()

别名引用方式,使用别名调用

  • import f "fmt"

  • 调用 f.Println()

省略引用方式,不需要包名或别名直接调用

  • import . "fmt"

  • 调用 Println()

包的init()函数

  • 包下可以有多个init()函数,包引入时会执行全部init(),但是init()不能保证执行顺序。

仅执行包下init()函数

引用包不使用就无法通过编译,如果要实现引用包调用init()但是不使用包也不报错可以使用缺省引入。

  • import _ "fmt"

  • 会执行fmt包下所有的init()函数。

包不能环形引用

  • 包之间不能出现环形引用,如a引用b,b引用c,c引用a,无法通过编译(import cycle not allowed)。。

包加载

  • 包初始化程序从main函数引用的包开始,逐级查找包的引用,直到找到没有引用其它包的包,最终生成一个引用的有向无环图。

  • Go编译器会将有向无环图转换为一棵树,然后从树的叶子节点开始逐层向上对包进行初始化。

  • 单个包初始化顺序,全局常量、包常量、全局变量、包变量、init()。

作用域

作用域(scope)是指标识符与标识符绑定的内存空间保持有效的那部分程序逻辑。

  • Golang 是静态作用域语言,静态作用域语言的标识符的作用域不依赖程序执行时的因素,标识符作用域在编译器就能确定。

全局作用域

全局变量、函数、方法

  • 任何地方都可以访问的标识符就是全局作用域,包括变量、常量、函数、方法。

  • 标识符首字母是大写的就是全局可访问的。

包内作用域

包内变量、函数、方法

  • 标识符定义在函数、方法之外并且首字母是小写即为包内作用域的变量、函数、方法。

  • 只能在包内访问,不同包无法访问。

局部作用域

局部变量

  • 变量定义在代码块{}之中(包括函数、方法、if {}...),代码块{}以外不可访问。

第三方包管理

  • 引入第三方库实现代码复用,加快开发速度。

  • go get 下载第三方库,Go1.6引入了vendor机制管理第三方包,后来推出dep工具,目前最优的是 go mod 第三方库管理。

go mod

  • go mod 使用 需要安装 git。

  • Go1.11开始实验go mod。

  • go mod 不再依靠 $GOPATH,使得它可以脱离 GOPATH 来创建项目。

  • Go 1.13 默认开启 Go modules。

go mod 相关命令

命令
描述

init

在当前目录项目下初始化mod

download

download modules to local cache(下载依赖包)

edit

edit go.mod from tools or scripts(编辑go.mod)

graph

print module requirement graph (打印模块依赖图)

tidy

add missing and remove unused modules(拉取缺少的模块,移除不用的模块)

vendor

make vendored copy of dependencies(将依赖复制到vendor下)

verify

verify dependencies have expected content (验证依赖是否正确)

why

explain why packages or modules are needed(解释为什么需要依赖)

go.mod 文件内提供了4个关键字

  • module 指定包的名字(路径)

  • require 指定依赖项模块

  • replace 替换依赖项模块

  • exclude 忽略依赖项模块

无法正常下载 配置代理

下载相关依赖如果网络失败,增加代理配置(如有VPN要关闭)。

  • 或者在终端输入 go env -w GOPROXY=https://goproxy.cn

如果还不行设置下面的环境变量,Windows 或者 Linux不同的设置方案。

  • Bash (Linux or macOS)

  • PowerShell (Windows)

  • 拉自建 github 包通常能解决问题的配置

go mod 维护了一个 go.sum 文件

  • 包含特定模块版本内容的预期加密哈希

  • go命令使用go.sum文件确保这些模块的未来下载检索与第一次下载相同的,以确保项目所依赖的模块不会出现意外更改,无论是出于恶意、意外还是其他原因。

  • go.mod和go.sum都应检入版本控制。go.sum 不需要人工维护。

go get 升级

go.mod中没有 require 包版本时,直接使用go get 包名 会直接下载,下载成功会将包自动 require ,如 【go get github.com/pkg/browser】

  • 运行 go get -u 将会升级到最新的次要版本或者修订版本(x.y.z, z是修订版本号, y是次要版本号)

  • 运行 go get -u=patch 将会升级到最新的修订版本

  • 运行 go get package@version 将会升级到指定的版本号version

  • 运行go get如果有版本的更改,那么go.mod文件也会更改

indirect 注释的含义

引入的包 如:

  • // indirect 注释的含义是指这个package被子module/package依赖,但main module没有直接使用,就是间接引用。

提交哈希引入

引入包版本 v0.0.0-20180826012351-8a410e7b638d,用得是提交时间和提交哈希,引入这种没有 release 版本的包可以写成 require 包名 提交哈希,go mod 会自动补齐版本的提交时间。

Last updated