在工程化的开发项目中,Go语言的源码复用是建立在包(package)基础之上的。

包(package)是多个Go源码的集合,是一种高级的代码复用方案,Go语言提供了很多内置包,如fmtosio等。

包的定义

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通脉之包的管理的更多相关文章

  1. Golang Gin 项目包依赖管理 godep 使用

    Golang Gin 项目包依赖管理 godep 使用 标签(空格分隔): Go 在按照github.com/tools/godep文档go get完包以后,调整项目结构为$GOPATH/src/$P ...

  2. golang多个项目时如何配置GOPATH,使用gb包依赖管理工具,不同项目配置不同的GOPATH的

    golang多个项目时如何配置GOPATH,使用gb包依赖管理工具,不同项目配置不同的GOPATH的 1:执行脚本setGoPath.sh#!/bin/bashif [[ $GOPATH =~ .*$ ...

  3. 一键解决 go get golang.org/x 包失败

    问题描述 当我们使用 go get.go install.go mod 等命令时,会自动下载相应的包或依赖包.但由于众所周知的原因,类似于 golang.org/x/... 的包会出现下载失败的情况. ...

  4. Go 包依赖管理工具 —— govendor

    govendor 是一个基于 vendor 机制实现的 Go 包依赖管理命令行工具.与原生 vendor 无侵入性融合,也支持从其他依赖管理工具迁移,可以很方便的实现同一个包在不同项目中不同版本.以及 ...

  5. [20150522]RPM包的管理

    RPM包的管理 RPM包的分类 RPM包可分为源码包和二进制包两类.源码包的主要优点是开源,如果有足够的能力,可以修改源代码,源码包可以自由选择所需要安装的功能,软件是编译安装,所以更加适合自己的系统 ...

  6. GridBagLayout:网格包布局管理器

    GridBagLayout:网格包布局管理器   GridBagLayout可以说是布局管理器Layout中最复杂的一个,其中涉及到的参数也比较得多,比如说: GridBagConstraints g ...

  7. Golang爬虫示例包系列教程(一):pedaily.com投资界爬虫

    Golang爬虫示例包 文件结构 自己用Golang原生包封装了一个爬虫库,源码见go get -u -v github.com/hunterhug/go_tool/spider ---- data ...

  8. 19-03【golang】strings包

    golang的strings包提供了字符串操作的一系列函数.下面做个简单介绍 函数 用法 备注 Compare(a,b sring) 比较两个字符串   Contains(s, substr stri ...

  9. 关于golang.org/x包问题

    关于golang.org/x包问题 由于谷歌被墙,跟谷歌相关的模块无法通过go get来下载,解决方法: git clone https://github.com/golang/net.git $GO ...

随机推荐

  1. 【Elasticsearch】.NetCore中Elasticsearch组件NEST的使用

    .NetCore中Elasticsearch组件NEST的使用 1. 安装Docker # 安装Docker curl -fsSL https://get.docker.com | bash -s d ...

  2. 痞子衡嵌入式:MCUXpresso IDE下工程链接文件配置管理与自动生成机制

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是MCUXpresso IDE下工程链接文件配置管理与自动生成机制. 痞子衡在 2018 年初写过一个专题 <嵌入式开发文件系列&g ...

  3. 软件测试2021:第一次作业——热身练习(Bug)

    案例一: 问题说明:在大学生服务外包创新创业大赛的注册页面填写密码的时候只有偶数位的密码可以通过验证,而基数位的密码不可以 原因分析:在密码验证的时候多加了一条验证,使得基数位的密码不能都通过验证 案 ...

  4. C# Dapper基本三层架构使用 (四、WinForm UI层)

    UI层主要功能是显示数据和接受传输用户的数据,可以在为网站的系统运行提供交互式操作界面,表示层的应用方式比较常见,例如Windows窗体和Web页面. 在项目中增加WinForm应用程序,结构如下 添 ...

  5. 通过url把第一个页面的数据传到第二页面

    第一个页面: function GetQueryString(name) { var reg = new RegExp("(^|&)"+ name +"=([^& ...

  6. .Net性能调优-ArrayPool

    定义 高性能托管数组缓冲池,可重复使用,用租用空间的方式代替重新分配数组空间的行为 好处 可以在频繁创建和销毁数组的情况下提高性能,减少垃圾回收器的压力 使用 获取缓冲池实例:Create/Share ...

  7. SpingBoot-Dubbo-Zookeeper-分布式

    目录 分布式理论 什么是分布式系统? Dubbo文档 单一应用架构 垂直应用架构 分布式服务架构 流动计算架构 什么是RPC RPC基本原理 测试环境搭建 Dubbo Dubbo环境搭建 Window ...

  8. oh,我的老伙计,你看看这近五十个dapr视频

    oh,我的老伙计,你看看这近五十个 dapr 视频.这不就是你想要的视频资料吗?快来捡走吧! 开始了,但是没完全开始 Dapr 是一个可移植的.事件驱动的运行时,它使任何开发人员能够轻松构建出弹性的. ...

  9. Weblogic漏洞分析之JNDI注入-CVE-2020-14645

    Weblogic漏洞分析之JNDI注入-CVE-2020-14645 Oracle七月发布的安全更新中,包含了一个Weblogic的反序列化RCE漏洞,编号CVE-2020-14645,CVS评分9. ...

  10. liunx常见指令

    linux目录结构 bin:存储普通命令 sbin:存储超级命令 home:存储普通用户 root:存储超级用户 usr /usr/local:下存储数据或软件,通常软件都放在其中 tmp:临时目录 ...