Golang通脉之包的管理
在工程化的开发项目中,Go语言的源码复用是建立在包(package)基础之上的。
包(package)是多个Go源码的集合,是一种高级的代码复用方案,Go语言提供了很多内置包,如fmt、os、io等。
包的定义
src 目录是以代码包的形式组织并保存 Go 源码文件的。每个代码包都和 src 目录下的文件夹一一对应。每个子目录都是一个代码包。
代码包包名和文件目录名,不要求一致。比如文件目录叫 server,但是代码包包名可以声明为 “main”,但是同一个目录下的源码文件第一行声明的所属包,必须一致!
还可以根据自己的需要创建自己的包。一个包可以简单理解为一个存放.go文件的文件夹。 该文件夹下面的所有go文件都要在代码的第一行添加如下代码,声明该文件归属的包。
package 包名
注意事项:
- 一个文件夹下面直接包含的文件只能归属一个
package,同样一个package的文件不能在多个文件夹下。 - 包名可以不和文件夹的名字一样,包名不能包含
-符号。 - 包名为
main的包为应用程序的入口包,这种包编译后会得到一个可执行文件,而编译不包含main包的源代码则不会得到可执行文件。 - 在同一个包下面的文件属于同一个工程文件,不用
import包,可以直接使用
可见性
如果想在一个包中引用另外一个包里的标识符(如变量、常量、类型、函数等)时,该标识符必须是对外可见的(public)。在Go语言中只需要将标识符的首字母大写就可以让标识符对外可见了:
package pkg
import "fmt"
// 包变量可见性
var a = 100 // 首字母小写,外部包不可见,只能在当前包内使用
// 首字母大写外部包可见,可在其他包中使用
const Mode = 1
type person struct { // 首字母小写,外部包不可见,只能在当前包内使用
name string
}
// 首字母大写,外部包可见,可在其他包中使用
func Add(x, y int) int {
return x + y
}
func age() { // 首字母小写,外部包不可见,只能在当前包内使用
var Age = 18 // 函数局部变量,外部包不可见,只能在当前函数内使用
fmt.Println(Age)
}
结构体中的字段名和接口中的方法名如果首字母都是大写,外部包可以访问这些字段和方法:
type Student struct {
Name string //可在包外访问的方法
class string //仅限包内访问的字段
}
type Payer interface {
init() //仅限包内访问的方法
Pay() //可在包外访问的方法
}
main包
Go 语言的入口 main() 函数所在的包(package)叫 main,main 包想要引用别的代码,需要import导入!
包的导入(import)
要在代码中引用其他包的内容,需要使用import关键字导入使用的包。具体语法如下:
A:通常导入
// 单个导入
import "package"
// 批量导入
import (
"package1"
"package2"
)
B:点操作 有时候会看到如下的方式导入包
import(
. "fmt"
)
这个点操作的含义就是这个包导入之后在你调用这个包的函数时,你可以省略前缀的包名,也就是前面你调用的fmt.Println("hello world")可以省略的写成Println("hello world")
注意事项:
- import导入语句通常放在文件开头包声明语句的下面。
- 导入的包名需要使用双引号包裹起来。
- 包名是从
$GOPATH/src/后开始计算的,使用/进行路径分隔。 - Go语言中禁止循环导入包。
自定义包名
自定义包名顾名思义可以把包命名成另一个用起来容易记忆的名字。导入时,可以为包定义别名,语法演示:
import (
p1 "package1"
p2 "package2"
)
// 使用时:别名操作,调用包函数时前缀变成了自定义的前缀
p1.Method()
匿名导入包
_ 操作 如果仅仅需要导入包时执行初始化操作,并不需要使用包内的其他函数,常量等资源。则可以在导入包时,匿名导入。
这个操作经常是让很多人费解的一个操作符:
import (
"database/sql"
_ "github.com/mysql/driver"
)
_操作其实是引入该包,而不直接使用包里面的函数,而是调用了该包里面的init函数。也就是说,使用下划线作为包的别名,会仅仅执行init()。
导入的包的路径名,可以是相对路径也可以是绝对路径,推荐使用绝对路径(起始于工程根目录)。
匿名导入的包与其他方式导入的包一样都会被编译到可执行文件中。
init()函数
init()函数介绍
在Go语言程序执行时导入包语句会自动触发包内部init()函数的调用。需要注意的是: init()函数没有参数也没有返回值。 init()函数在程序运行时自动被调用执行,不能在代码中主动调用它,init() 中的代码会在 main() 函数执行前执行,用于初始化包所需要的特定资源。
包初始化执行的顺序如下图所示:

init()函数执行顺序
Go语言包会从main包开始检查其导入的所有包,每个包中又可能导入了其他的包。Go编译器由此构建出一个树状的包引用关系,再根据引用顺序决定编译顺序,依次编译这些包的代码。
在运行时,被最后导入的包会最先初始化并调用其init()函数, 如下图示:

禁止循环引用包:A -> B -> C -> A
init函数与main函数的异同
相同点:
- 两个函数在定义时不能有任何的参数和返回值。 都只能由 go 程序自动调用,不可以被引用。
不同点:
init 可以应用于任意包中,且可以重复定义多个。 main 函数只能用于 main 包中,且只能定义一个。
两个函数的执行顺序:
在 main 包中的 go 文件默认总是会被执行。对同一个 go 文件的 init( ) 调用顺序是从上到下的。
对同一个 package 中的不同文件,将文件名按字符串进行“从小到大”排序,之后顺序调用各文件中的init()函数。
对于不同的 package,如果不相互依赖的话,按照 main 包中 import 的顺序调用其包中的 init() 函数。
如果 package 存在依赖,调用顺序为最后被依赖的最先被初始化,例如:导入顺序 main –> A –> B –> C,则初始化顺序为 C –> B –> A –> main,一次执行对应的 init 方法。main 包总是被最后一个初始化,因为它总是依赖别的包
Golang通脉之包的管理的更多相关文章
- Golang Gin 项目包依赖管理 godep 使用
Golang Gin 项目包依赖管理 godep 使用 标签(空格分隔): Go 在按照github.com/tools/godep文档go get完包以后,调整项目结构为$GOPATH/src/$P ...
- golang多个项目时如何配置GOPATH,使用gb包依赖管理工具,不同项目配置不同的GOPATH的
golang多个项目时如何配置GOPATH,使用gb包依赖管理工具,不同项目配置不同的GOPATH的 1:执行脚本setGoPath.sh#!/bin/bashif [[ $GOPATH =~ .*$ ...
- 一键解决 go get golang.org/x 包失败
问题描述 当我们使用 go get.go install.go mod 等命令时,会自动下载相应的包或依赖包.但由于众所周知的原因,类似于 golang.org/x/... 的包会出现下载失败的情况. ...
- Go 包依赖管理工具 —— govendor
govendor 是一个基于 vendor 机制实现的 Go 包依赖管理命令行工具.与原生 vendor 无侵入性融合,也支持从其他依赖管理工具迁移,可以很方便的实现同一个包在不同项目中不同版本.以及 ...
- [20150522]RPM包的管理
RPM包的管理 RPM包的分类 RPM包可分为源码包和二进制包两类.源码包的主要优点是开源,如果有足够的能力,可以修改源代码,源码包可以自由选择所需要安装的功能,软件是编译安装,所以更加适合自己的系统 ...
- GridBagLayout:网格包布局管理器
GridBagLayout:网格包布局管理器 GridBagLayout可以说是布局管理器Layout中最复杂的一个,其中涉及到的参数也比较得多,比如说: GridBagConstraints g ...
- Golang爬虫示例包系列教程(一):pedaily.com投资界爬虫
Golang爬虫示例包 文件结构 自己用Golang原生包封装了一个爬虫库,源码见go get -u -v github.com/hunterhug/go_tool/spider ---- data ...
- 19-03【golang】strings包
golang的strings包提供了字符串操作的一系列函数.下面做个简单介绍 函数 用法 备注 Compare(a,b sring) 比较两个字符串 Contains(s, substr stri ...
- 关于golang.org/x包问题
关于golang.org/x包问题 由于谷歌被墙,跟谷歌相关的模块无法通过go get来下载,解决方法: git clone https://github.com/golang/net.git $GO ...
随机推荐
- spring boot 系列之七:SpringBoot整合Mybatis
springboot已经很流行,但是它仍需要搭配一款ORM框架来实现数据的CRUD,之前已经分享过JdbcTemplete和JPA的整合,本次分享下Mybatis的整合. 对于mybatis的使用,需 ...
- java多线程 synchronized 与lock锁 实现线程安全
如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的. 通过卖火车票的例子 火车站要卖票,我们模 ...
- Servlet生命周期和方法
一.五个生命周期方法,有三个很重要,初始化方法.提供服务方法和销毁方法 1.三个主要方法 2.另外两个重写的成员方法只做了解 二.生命周期详解 其中,每次刷新页面都是一次对servlet访问: 页面访 ...
- JAVA反序列化漏洞基础原理
JAVA反序列化漏洞基础原理 1.1 什么是序列化和反序列化? Java序列化是指把Java对象转换为字节序列的过程: Java反序列化是指把字节序列恢复为Java对象的过程: 1.2 为什么要序列化 ...
- Vue组件传值(三)之 深层嵌套组件传值 - $attrs 和 $listeners
$attrs 包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外).当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class和 ...
- 手动制作Docker镜像
手动制作 Docker 镜像 前言 a. 本文主要为 Docker的视频教程 笔记. b. 环境为 CentOS 7.0 云服务器(用来用去感觉 Windows 的 Docker 出各种问题,比如使用 ...
- 基于swoole框架hyperf开发的纯API接口化的后台RBAC管理工具hyperfly@v1.0.0发布
hyperfly@v1.0.0发布 本文地址http://yangjianyong.cn/?p=323转载无需经过作者本人授权 github地址:https://github.com/vankour/ ...
- 38KHz,NEC红外模拟发送和接收程序
/*************************************************************************************************/ ...
- Spring Cloud Hystrix 学习(一)
在学习Hystrix之前,首先引入一个问题场景,服务雪崩.如下图所示: 可以看到,三个入口服务A.B.C最终都会请求到服务T.当服务T的请求过载,打满CPU都无法匹配请求的频率时,同步调用的上级服务就 ...
- 【PHP数据结构】栈的相关逻辑操作
对于逻辑结构来说,我们也是从最简单的开始.堆栈.队列,这两个词对于大部分人都不会陌生,但是,堆和栈其实是两个东西.在面试的时候千万不要被面试官绕晕了.堆是一种树结构,或者说是完全二叉树的结构.而今天, ...