彻底理解 Go 的包概念

包的概念

包是结构化代码的一种方式:每个程序都由包(通常简称为 pkg)的概念组成,可以使用自身的包或者从其它包中导入内容。

如同其它一些编程语言中的类库或命名空间的概念,每个 Go 文件都属于且仅属于一个包。一个包可以由许多以 .go 为扩展名的源文件组成,因此文件名和包名一般来说都是不相同的。

你必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main 。

package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。package main包下可以有多个文件,但所有文件中只能有一个main()方法,main()方法代表程序入口。

一个应用程序可以包含不同的包,而且即使你只使用 main 包也不必把所有的代码都写在一个巨大的文件里:你可以用一些较小的文件,并且在每个文件非注释的第一行都使用 package main 来指明这些文件都属于 main 包。如果你打算编译包名不是为 main 的源文件,如 pack1,编译后产生的对象文件将会是 pack1.a 而不是可执行程序。另外要注意的是,所有的包名都应该使用小写字母。当然,main包是不能在其他文档import的,编译器会报错:

import "xx/xx" is a program, not an importable package。

简单地说,在含有mian包的目录下,你可以写多个文件,每个文件非注释的第一行都使用 package main 来指明这些文件都属于这个应用的 main 包,只有一个文件能有mian() 方法,也就是应用程序的入口。main包不是必须的,只有在可执行的应用程序中需要。

包的导入

一个 Go 程序是通过 import 关键字将一组包链接在一起。

import “fmt” 告诉 Go 编译器这个程序需要使用 fmt 包(的函数,或其他元素),fmt 包实现了格式化 IO(输入/输出)的函数。包名被封闭在半角双引号 “” 中。如果你打算从已编译的包中导入并加载公开声明的方法,不需要插入已编译包的源代码。

import 其实是导入目录,而不是定义的package名字,虽然我们一般都会保持一致,但其实是可以随便定义目录名,只是使用时会很容易混乱,不建议这么做。

例如:package big ,我们import “math/big” ,其实是在src中的src/math目录。在代码中使用big.Int时,big指的才是Go文件中定义的package名字。

当你导入多个包时,最好按照字母顺序排列包名,这样做更加清晰易读。

如果包名不是以 ./ ,如 “fmt” 或者 “container/list”,则 Go 会在全局文件进行查找;如果包名以 ./ 开头,则 Go 会在相对目录中查找。

导入包即等同于包含了这个包的所有的代码对象。

除了符号 _,包中所有代码对象的标识符必须是唯一的,以避免名称冲突。但是相同的标识符可以在不同的包中使用,因为可以使用包名来区分它们。

导入包的路径的几种情况:

  • 第一种方式相对路径

    `import   "./module"   //当前文件同一目录的module目录, 此方式没什么用容易出错,不建议用`
  • 第二种方式绝对路径

import  "LearnGo/init"  //加载Gopath/src/LearnGo/init模块,一般建议这样使用""

导入多个包的常见的方式是:

import  (
"fmt"
"net/http"
 )

包的分级声明和初始化

你可以在使用 import 导入包之后定义或声明 0 个或多个常量(const)、变量(var)和类型(type),这些对象的作用域都是全局的(在本包范围内),所以可以被本包中所有的函数调用,然后声明一个或多个函数(func)。

如果存在 init 函数的话,则对该函数进行定义(这是一个特殊的函数,每个含有该函数的包都会首先执行这个函数)。

程序开始执行并完成初始化后,第一个调用(程序的入口点)的函数是 main.main()(如果有 init() 函数则会先执行该函数)。

如果你的 main 包的源代码没有包含 main 函数,则会引发构建错误 undefined: main.main。main 函数既没有参数,也没有返回类型,这一点上 init 函数和 main 函数一样。

main函数一旦返回就表示程序已成功执行并立即退出。

Go 程序的执行(程序启动)顺序如下:\
程序的初始化和执行都起始于main包。如果main包还导入了其它的包,那么就会在编译时将它们依次导入。有时一个包会被多个包同时导入,那么它只会被导入一次(例如很多包可能都会用到fmt包,但它只会被导入一次,因为没有必要导入多次)。当一个包被导入时,如果该包还导入了其它的包,那么会先将其它包导入进来,然后再对这些包中的包级常量和变量进行初始化,接着执行init函数(如果有的话),依次类推。等所有被导入的包都加载完毕了,就会开始对main包中的包级常量和变量进行初始化,然后执行main包中的init函数(如果存在的话),最后执行main函数。

Go语言中init函数用于包(package)的初始化,该函数是Go语言的一个重要特性,有下面的特征:

  • init函数是用于程序执行前做包的初始化的函数,比如初始化包里的变量等
  • 每个包可以拥有多个init函数
  • 包的每个源文件也可以拥有多个init函数
  • 同一个包中多个init函数的执行顺序Go语言没有明确的定义(说明)
  • 不同包的init函数按照包导入的依赖关系决定该初始化函数的执行顺序
  • init函数不能被其他函数调用,而是在main函数执行之前,自动被调用
mushu
讨论数量: 1
yourself

关于包应该是有一个规范的:
例:
src/域名或名称/账户名/项目名称

这样就很好的解决了引入的问题

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!