Go语言包管理(一)

Go语言中的包

我们在使用其他语言,比如Java,Python,都有类似包的概念,Go也不例外,其核心思想即为分组和模块化。人的大脑对庞大和复杂的事情很难掌控,可以对其采用分而治之的策略,使其模块化,从而更容易管理。 如下是标准库中net包的树形结构图

net
├─http
│ ├─cgi
│ │ └─testdata
│ ├─cookiejar
│ ├─fcgi
│ ├─httptest
│ ├─httptrace
│ ├─httputil
│ ├─internal
│ ├─pprof
│ └─testdata
├─internal
│ └─socktest
├─mail
├─rpc
│ └─jsonrpc
├─smtp
├─testdata
├─textproto
└─url

库包和main包

当把一个程序的package声明为main的时候(并且该文件包含一个main函数),则表示最终该程序要编译为一个可执行的程序。如果程序未声明为main,则可以编译为一个库的形式。

包的导入

通过import导入包之后,即可使用包中的变量和函数,如下源码,我们定义了一个lib包,里面定义了加,减,乘,除4个方法,然后在另一个包中来使用。

库中的内容如下:

package lib1

func Add(x, y int) int {
    z := x + y
    return z
}

func Sub(x, y int) int {
    z := x - y
    return z
}

func Mul(x, y int) int {
    z := x * y
    return z
}

func Div(x, y int) int {
    z := x / y
    return z
}

main包的内容如下:

package main

import (
    "fmt"
    "lib1"
)

func main() {
    x := 8
    y := 2

    a := lib1.Add(x, y)
    b := lib1.Sub(x, y)
    c := lib1.Mul(x, y)
    d := lib1.Div(x, y)

    fmt.Println(a)
    fmt.Println(b)
    fmt.Println(c)
    fmt.Println(d)
}

输出:

10
6
16
4

注意库包中导出的方法若想让包外可见,则第一个字母要大写。如Add,Sub… 否则该方法对包外不可见,仅可在本包中使用(变量也有同样的原则)。Go语言没有提供类似C++和Java的private,public,protected等关键字,也反应了Go语言的哲学思想:简单实用至上。

包名导入冲突(命名导入)

在使用import导入包的时候,我们就可以通过包名称引用包中的方法,如上面的lib1,但是如果有又有另一个人开发的包名称也为lib1(这里只包的最后一部分),也就是发生的包命名冲突该如何处理呢。可以在import的名称前面起一个别名处理此问题,如下分别把“fmt”和“lib1”的包名称重新命名为了“fmta”和“liba”

package main

import (
    fmta "fmt"
    liba "lib1"
)

func main() {
    x := 8
    y := 2

    a := liba.Add(x, y)
    b := liba.Sub(x, y)
    c := liba.Mul(x, y)
    d := liba.Div(x, y)

    fmta.Println(a)
    fmta.Println(b)
    fmta.Println(c)
    fmta.Println(d)
}

包的初始化函数 init()

一个包中可能有多个文件,如果我们想对这个包做一些初始化操作该如何做呢?Go提供了一个既没有参数也没有返回值的init()函数(类似main函数), 可以在init函数中进行初始化操作。 比如有如下3个包“lib1”,“lib2”“m1”分别代表两个库包和一个包含main函数的主包,每个包中有对应的Go文件,包目录结构如下:

├─lib1 a.go
├─lib2 b.go
└─m1 m.go

“m1”包中的m.go文件会import“lib1”,进一步“lib1”会import“lib2”。且在lib1和lib2中定义了init函数。源码如下:

//lib2中的a2.go

package lib2

import (
    "fmt"
)

func init() {
    fmt.Println("lib2 init1")
}

func init() {
    fmt.Println("lib2 init2")
}
// lib1中的a1.go
package lib1

import (
    "fmt"
    _ "lib2"
)

func init() {
    fmt.Println("lib1 init1")
}

func init() {
    fmt.Println("lib1 init2")
}
//m1中的m.go
package main

import (
    "fmt"
    _ "lib1"
)

func main() {
    fmt.Println("main")
}

输出:

lib2 init1
lib2 init2
lib1 init1
lib1 init2
main

可见main最后执行,首先执行的是import各个包时候的init。而且init函数执行的顺序是依据依赖顺序来执行的。Go会递归对依赖进行分析,然后从main包开始分析,首先保证没有循环依赖。main包发现import了“lib1”,lib1发现又import了“lib2”,因此首先执行lib2的init函数,再返回执行lib1中的init函数,最后返回到main函数来执行。

每个包中可以有多个文件,每个文件中也可以有多个init()函数,但是这些init函数的顺序Go是没有保证的。

包的匿名导入

因为Go对导入但是未使用的包,会报编译错误。因此可以使用如下的方式。在包名称之前使用一个下划线”_”来表示。这样仍然会执行所import包中的init函数。

package lib1

import (
    "fmt"
    _ "lib2"
)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值