以前看golang包管理时,感觉有点混乱,套用python,lua包管理的方式不行,直到今天(2018.10.19)才基本搞清楚golang包管理的意思。
使用包package目的
使用包的目的是为了更加方便的管理源码。golang的理念是用文件夹来管理(或者叫约束)同种类型或同种功能的源码,例如数学计算的源码都放入math文件夹下,系统相关的放入os文件夹下。
一个文件夹下的源码中所有包名必须一样,但是包名可以与文件名不一样。例如项目中涉及到数学计算,建立一个文件夹为math,为了让功能独立,我们每一个功能使用一个go文件,诸如add.go,sub.go,div.go等。一个go文件必须要在开头指定所在的包,语法为package xxx,我们可以写为package "mymath"。
如何使用包管理
如何使用上面的math模块呢? 如果是在同一个文件夹中(肯定也是在同一个package中),直接调用相关函数或全局变量,而不用加包名限制,加了反而出错。 如果不是同一个文件夹(注意不在同一个文件下,不能用一个包名),则首先要import该文件夹,然后使用包名限制来使用函数或者全局变量,例如mymath.Add()
还有一个问题是,import math文件夹不会包含math文件夹下的子文件夹的源文件,也就是说如果想要包含文件夹下子文件,则要import指定到子文件夹名。同时子文件夹中源码的package包名也必须不一样。引用子文件夹中的源码时不必带上父文件夹中的包名,直接用包名即可。
import的本质:
import实际上是按顺序解析文件夹中所有的源文件。当一个源文件还导入了其它的包,那么先将其他的包导入进来。那么有三个问题要弄清楚:
- 同一个文件多次引入的问题。例如,math文件夹下有a,b,c三个文件,a,b,c又同时import了另外一个文件夹other。那么当import math时,会多次引入other文件夹下的文件吗?答案是不会,一个文件只会被引入一次。
- 循环引用的问题。例如math文件夹下的a文件源码引用了other文件夹,other文件夹中的文件又引用math。这种情况下该如何处理,循环递归直至crash吗?幸好,import机制不允许循环引用。所以不必担心这个问题。
- 解析源文件时做了什么? 常量和变量进行初始化,最后执行init函数,如果存在的话(init函数不能主动被调用,无论是调用自己包中还是其他包中的)。 用一个图表示上面的过程:
import修饰操作
- 点(.)操作
点(.)操作的含义是:点(.)标识的包导入后,调用该包中函数时可以省略前缀包名。点(.)操作的语法为:
import . "package1"
import . "package2"
import . "package3"
...
import (
. "package1"
. "package2"
. "package3"
...
)
下面的示例中,fmt包将使用点操作省略前缀包名,os包用法保持不变:
package main
import (
. "fmt"
"os"
)
func main() {
for _, value := range os.Args {
Println(value)
}
}
- 别名操作
别名操作的含义是:将导入的包命名为另一个容易记忆的别名。别名操作的语法为:
import p1 "package1"
import p2 "package2"
import p3 "package3"
...
import (
p1 "package1"
p2 "package2"
p3 "package3"
...
)
下面的示例中,fmt包将使用别名操作重新命名为f,os包用法保持不变:
package main
import (
f "fmt"
"os"
)
func main() {
for _, value := range os.Args {
f.Println(value)
}
}
- 下划线(_)操作
下划线()操作的含义是:导入该包,但不导入整个包,而是执行该包中的init函数,因此无法通过包名来调用包中的其他函数。使用下划线()操作往往是为了注册包里的引擎,让外部可以方便地使用。下划线(_)操作的语法为:
import _ "package1"
import _ "package2"
import _ "package3"
...
import (
_ "package1"
_ "package2"
_ "package3"
...
)
参考:
有疑问加站长微信联系(非本文作者)