一、Package

Go语言中的包(Package)就像其它语言的库(Library)或模块(Module)一样,支持模块化,封装性,可重用性,单独编译等特点。包的源码是由数个.go文件组成,这些文件所在的目录名是import路径的最后一个词,例如github.com/sunface/corego包的所有文件都存储在$GOPATH/src/github.com/sunface/corego底下。

每个包都有独立的命名空间。例如,在image包中的Decode和unicode/utf16中的Decode是完全不同的函数。如果要引用第三方库的函数,我们要使用package.Func的形式,例如image.Decode和utf16.Decode。

包也允许我们自己控制包内变量、函数的可见性。在Go语言中,变量、函数等的导出只取决于一个因素:名字首字母的大小写。

想象一下,如果我们的温度转换软件开始流行了,然后希望贡献给开源社区,应该怎么做?

首先让我们创建一个包github.com/sunface/temconv,在1.3节的例子基础上做一些变化。这个包中包含了两个文件,演示了怎么样把数据声明和数据访问分开,在现实项目中,这个包实际只需要一个文件。

temconv.go包含了类型声明,常量,类型的method:

package tempconvimport "fmt"type Celsius float64
type Fahrenheit float64const (AbsoluteZeroC Celsius = -273.15FreezingC     Celsius = 0BoilingC      Celsius = 100
)func (c Celsius) String() string    { return fmt.Sprintf("%g°C", c) }
func (f Fahrenheit) String() string { return fmt.Sprintf("%g°F", f) }

conv.go包含了转换函数:

//温度转换
package tempconv// 将Celsius温度转换为Fahrenheit
func CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9/5 + 32) }// 将Fahrenheit温度转换为Celsius.
func FToC(f Fahrenheit) Celsius { return Celsius((f - 32) * 5 / 9) }

每个.go文件的第一行都是package tempconv的声明,表示该文件属于哪个包。当包被导入后,可以这样调用它的成员:tempconv.CToF等等。包级别的变量,例如类型、常量等,对同一个包内的所有文件都是可见的,就好像所有代码定义在同一个文件中一样。注意这里temconv.go导入了fmt.但是conv.go没有,因为它没有用到fmt的任何成员。

上面代码中包级别的const变量,都是大写字母开头的,因此可以在temconv包的外部使用,tempconv.AbsoluteZeroC:

fmt.Println(tempconv.CToF(tempconv.BoilingC)) // "212°F"

我们会选择包内的某个.go文件进行包级别的注释,注释写在该文件的package声明前(见之前的conv.go)。一般来说,这里的注释是对文件进行概述的。一个包只有一个文件需要包级别的注释。这些注释一般会放在doc.go文件中,后续可以通过go doc tempconv来查看包注释。

二、包导入(import)

在Go程序中,每一个包都是通过一个唯一的字符串来标示的,被称为导入路径,这些包是在import声明中统一导入的。Go语言规范不会对导入的包名进行任何约定,这些是由Go的工具来完成解析的。当使用go的工具 (tool)时,一个导入路径代表了一个文件夹,该文件夹内包含了组成包的.go文件。

在import声明中,每个包都有自己的导入包名,按照惯例,这个包名是导入路径的最后一个词,例如github.com/sunface/tempconv的导入包名是temconv:

package mainimport ("fmt""os""strconv""github.com/sunface/tempconv"
)func main() {for _, arg := range os.Args[1:] {t, err := strconv.ParseFloat(arg, 64)if err != nil {fmt.Fprintf(os.Stderr, "cf: %v\n", err)os.Exit(1)}f := tempconv.Fahrenheit(t)c := tempconv.Celsius(t)fmt.Printf("%s = %s, %s = %s\n",f, tempconv.FToC(f), c, tempconv.CToF(c))}
}

因此可以直接调用tempconv.CToF。还可以使用别名机制避免包名冲突:

import ("github.com/sunface/tempconv"temp "github.com/sunfei/tempconv"
)

调用github.com/sunfei/tempconv:temp.CToF;调用github.com/sunface/tempconv:tempconv.CToF。

上面这个程序将单独的数字命令行参数转换成Celsius和Fahrenhit的值。

$ go build github.com/sunface/corego/ch1.4/cf
$ ./cf 32
32°F = 0°C, 32°C = 89.6°F
$ ./cf 212
212°F = 100°C, 212°C = 413.6°F
$ ./cf -40
-40°F = -40°C, -40°C = -40°F

如果导入一个包后不去使用,那么就会报编译错误,编译器的这个检查可以帮助消除不需要的包引用,虽然在debug期间可能会比较蛋疼,例如注释掉log.Print("hello")可能会消除程序对log包的引用,这个时候编译器就会报错。还好,我们可以使用golang.org/x/tools/cmd/goimports工具,它会自动插入和移除包引用,大多数ide都支持配置去使用goimports。

三、包的初始化

包的初始化时会按照声明的顺序初始化包级别的变量,除非变量间有依赖顺序:

var a = b + c     // a 第三个初始化 3
var b = f()       // b 第二个初始化,调用了f
var c = 1         // c 第一个初始化func f() int { return c + 1 }

如果某个包有多个.go文件,那这些文件会按照提交给编译器的顺序来初始化,在唤醒编译器前,go tool会通过文件名对.go文件进行排序。

任何文件都可以包含任何数目的init函数:

func init() { /* ... */ }

这种init函数不能被调用也不能被引用,在每个文件内,init函数都会在程序刚启动的时候自动运行,文件内每个init函数会按照声明的顺序依次执行。

每个包只会被初始化一次,首先是初始化依赖包,如果包p导入q,可以肯定的是:q在p初始化之前肯定会完全初始化。因为依赖包会先初始化,所以程序的初始化是自底向上的,main包肯定是最后一个初始化(包的组织类似一个树形结构,main是根节点)。这样在main函数开始时,所有的包都会初始化完毕!

文章所有权:Golang隐修会 联系人:孙飞,CTO@188.com!

Go语言核心之美 1.4-包和文件相关推荐

  1. Go语言核心之美-必读

    Go语言核心之美开篇了!,无论你是新手还是一代高人,在这个系列文章中,总能找到你想要的! 博主是计算机领域资深专家并且是英语专8水平,翻译标准只有三个:精确.专业.不晦涩,为此每篇文章可能都要耗费数个 ...

  2. Go语言核心之美 1.5-作用域

    变量的作用域是指程序代码中可以有效使用这个变量的范围.不要将作用域和生命期混在一起.作用域是代码中的一块区域,是一个编译期的属性:生命期是程序运行期间变量存活的时间段,在此时间段内,变量可以被程序的其 ...

  3. [日常] go语言圣经-声明,变量,赋值,类型,包和文件习题

    go语言圣经-声明 1.四种类型的声明语句:var.const.type和func,分别对应变量.常量.类型和函数实体对象的声明 2.包一级声明语句声明的名字可在整个包对应的每个源文件中访问,局部声明 ...

  4. Go语言核心之美 3.4-Struct结构体

    struct(结构体)也是一种聚合的数据类型,struct可以包含多个任意类型的值,这些值被称为struct的字段.用来演示struct的一个经典案例就是雇员信息,每条雇员信息包含:员工编号,姓名,住 ...

  5. Go语言核心之美 2.6-常量

    在Go语言中,常量表达式是在编译期求值的,因此在程序运行时是没有性能损耗的.常量的底层类型是前面提过的基本类型:布尔值,字符串,数值变量. 常量的声明方式和变量很相似,但是常量的值是不可变的,因此在运 ...

  6. Go语言核心之美 3.3-Map

    哈希表是一种非常好用.适用面很广的数据结构,是key-value对的无序集合.它的key是唯一的,通过key可以在常数复杂度时间内进行查询.更新或删除,无论哈希表有多大. Go语言的map类型就是对哈 ...

  7. Go语言核心之美 1.2-变量及声明篇

    变量 1.声明变量 使用var关键字可以创建一个指定类型的变量: var i int = 0 var i = 0 var i int 以上三个表达式均是合法的,第三个表达式会将i初始化为int类型的零 ...

  8. Go语言核心之美 2.1-整数

    第二章 序 在计算机底层,一切都是比特位.然而计算机一般操作的都是固定大小的值,称之为字(word).字会被解释为整数.浮点数.比特位数组.内存地址等,这些字又可以进一步聚合成数据包(packet). ...

  9. Go语言核心之美 2.5-字符串

    字符串是不可变的字节序列,虽然可以包含任意数据,包括0这个字节,不过字符串通常是用来包含可读性较强的文本.文本字符串通常采用UTF-8编码,由Unicode码点(rune)组成. 内置的len函数会返 ...

最新文章

  1. 懒人必备:.NetCore快速搭建ELK分布式日志中心
  2. 技术解析系列 PouchContainer Goroutine Leak 检测实践
  3. 新手入门Web前端要掌握的4项基础技能
  4. OCA第4部分中的Java难题
  5. 计算机上无线网络开关在哪里,笔记本电脑无线网开关在哪_笔记本电脑如何打开无线网-win7之家...
  6. Codeforces Round #467 (Div. 1): B. Sleepy Game(BFS+有向图判环)
  7. Html5 の 微信飞机大战
  8. 实验报告二:例2-19 一位全加器
  9. java数据结构与算法总结(二十五)--初识BitSet之API
  10. VC dll依赖性查看工具depends
  11. python删除表格重复行_python 删除excel表格重复行,数据预处理操作
  12. python unpacking_使用Python将数组的元素导出到变量中(unpacking)
  13. python实现树结构并显示
  14. 视频 TS 内容详细讲解
  15. 学习笔记:UDP实现进程心跳检测
  16. 云原生,炸裂!(文末有福利)
  17. Vegas使用技巧—— 如何实现三维立体调整?
  18. pytorch 回归问题实战
  19. Oracle入门知识
  20. Retinanet训练Pascal VOC 2007

热门文章

  1. 编程实践--决策树分类算法--隐形眼镜材质分类
  2. CSS3 实现3D特效
  3. android视频播放边播边缓存
  4. Application Repository一键启用微信告警通知
  5. 二叉树的左视图-java
  6. 2019成长复盘2020成长规划
  7. 计算机比赛小组名称和口号,小组名称口号大全(精选150个)
  8. GPIB编程控件指令
  9. Vue-第三方库扩展
  10. sqlserver中如何提取datetime格式数据中的日期或时间?