Go通过包(package)的⽅式来组织和管理源码,任何⼀个源码必须属于⼀个包,更其他语言的包功能类似,包的作用把相关功能的代码组织在一个包文件下,包名在源文件中第一行通过关键字package指定,包名一般建议小写

  1. package 包名称

每个目录下面可以有多个.go文件,这些文件只能属于同一个包。同一个包下的不同.go文件相互之间可以直接引用变量和函数,所以这些文件中定义的全局变量和函数不能重名。

包导入

导入包需要将包名称用引号,导入包主要可分为两种方式,

  • 单行导入

    1. import "fmt"
    2. import "sync"
  • 多行导入

    1. import(
    2. "fmt"
    3. "sync"
    4. )

    main包

    可执⾏程序入口的的包名必须为main,而且在main包中必须且只能有一个main()函数,main()函数就是应用程序运行开始入口

  1. package main
  2. import "fmt"
  3. func main() {
  4. fmt.Println("hello golang")
  5. }

⾃定义包

⽤户可以写⾃定义包,⾃定义包编译成静态库,一般建议自定义包的名称就是文件目录的名称。

  1. package utils
  2. import (
  3. "crypto/md5"
  4. "encoding/hex"
  5. )
  6. func EncodeMD5(value string) string {
  7. m := md5.New()
  8. m.Write([]byte(value))
  9. return hex.EncodeToString(m.Sum(nil))
  10. }

应用自定义包的函数,导出变量或函数。⾸字⺟⼤写表示可导出,⼩写表示私有。不能被外部的包访问

  1. package main
  2. import (
  3. "fmt"
  4. "github.com/baxiang/go-note/utils"
  5. )
  6. func main() {
  7. fmt.Println(utils.EncodeMD5("hello golang"))
  8. }

注意 如果对外提供的函数 需要首字母大写,否则自定义包函数是如无法被其他包引用的

使用别名

在一些场景下,我们可能需要对导入的包进行重新命名,比如

  • 我们导入了两个具有同一包名的包时产生冲突,此时这里为其中一个包定义别名
  1. import (
  2. "crypto/rand"
  3. mrand "math/rand" // 将名称替换为mrand避免冲突
  4. )
  • 我们导入了一个名字很长的包,为了避免后面都写这么长串的包名,可以这样定义别名
  1. import hw "helloworldtestmodule"
  • 防止导入的包名和本地的变量发生冲突,比如 path 这个很常用的变量名和导入的标准包冲突。
  1. import pathpkg "path"

包的初始化

每个包都允许有一个 init 函数,当这个包被导入时,会执行该包的这个 init 函数,做一些初始化任务。
对于 init 函数的执行有两点需要注意

  1. init()函数不能被其他函数调用,init 函数优先于 main 函数之前会自动执行。
  2. 不同包的init()函数按照包导入的依赖关系决定该函数的执行顺序比如,有这样一个包引用关系:main→A→B→C,那么初始化顺序为
    1. C.initB.initA.initmain

包的匿名导入

当我们导入一个包时,如果这个包没有被使用到,在编译时,是会报错的。
但是有些情况下,我们导入一个包,只想执行包里的 init 函数,来运行一些初始化任务,此时怎么办呢?
可以使用匿名导入,用法如下,其中下划线为空白标识符,并不能被访问
// 注册一个PNG decoder

  1. import _ "image/png"

由于导入时,会执行 init 函数,所以编译时,仍然会将这个包编译到可执行文件中。

参考

https://github.com/iswbm/GolangCodingTime/blob/master/source/c03/c03_04.md