Go语言学习2----代码组织之包


上一篇文件中已经学习到go语言的工程结构,都是放在GOPATH下的src目录下,大部分高级编程语言都有包的概念像java、python等,即使没有包的概念源码也会以不同的目录来组织以方便大型软件源码的管理,像c/c++等。go语言也是有包的概念的,个人感觉与java的包比较类似。所谓的包就是源代码所在的相对路径


源码文件

包只是组织源码文件的形式,所以首先要熟悉源码文件。Go语言的源码文件分为三类:命令源码文件、库源码文件和测试源码文件。

注意:Go源码文件需要以UTF-8编码存储。

命令源码文件

  • 被声明为属于main代码包且代码中包含无参数声明和结果声明的main函数,相当于程序的入口。
  • 同一个代码包中可以有多个命令源码文件,可以通过go run命令后面加上相应命令源码文件名来分别运行
  • 同一个代码包中如果有多个命令源码文件,则go build和go install命令无法编译和安装该代码包。
  • 如果命令源码文件和库源码文件(定义后面给出)处于同一个代码包中,则go build和go install命令无法编译和安装该代码包。

根据以上要求,一般情况下将命令源码文件放在单独的包中,并且如果有多个命令源码文件的话也都单独存放在不同的包中。

库源码文件

  • 声明的包名会与它实际所属的代码包(目录)名一致,且代码中不包含无参数声明和结果声明的main函数
  • go install命令安装库源码文件时,是以整个包一起编译并归档,归档文件名以包的最后一级目录名命名,后缀为“.a”,归档目录为工作区下的pkg的平台相关目录下

测试源码文件

  • 是一种特殊的库源码文件,可以通过go test命令运行当前代码包下的所有测试源码文件
  • 测试源码文件必须以"XXX_test.go"形式命令,即必须以“_test.go”结尾。
  • 文件中需要至少包含一个名称以“Test”开头或者“Benchmark”开头、拥有一个类型为“testing.T”或者“testing.B”的参数的函数。

代码包

Go语言中的代码包是对代码进行构建和打包的基本单元。

包声明

  • 与java等语言一样,go的包声明关键字为package
  • 与java不一样的地方是,go语言的包名为源码文件所在路径的最后一级目录的目录名(即源码文件所在目录的目录名,而不是多个目录名以“.”连接)
  • 命令源码文件不管在哪个包中,其声明的包名都必须是main包

包导入

  • 与java等语言一样,go的包导入关键字为import
  • java语言的import只能导入文件(导入路径以文件名结束,或者以“*”号结束),而go语言只能导入包名
  • 代码包的导入使用代码包导入路径,导入路径就是工作区下的src目录下的相对路径。例如go源码文件所在路径为$GOPATH/src/hello/log/logging.go,则此源码文件的导入路径为hello/log
  • 当导入多个代码包时,即可以对每个代码包都使用import关键字,也可以所有需要导入的代码包共用一个import关键字,后一种需要用圆括号把包名括起来,并且每个包名也是独占一行
  • 调用导入包中的变量或者函数方法:<导入包名中最后一个目录名称>.<变量名/函数名>

import "a/b"
import "a/c"

与下面是等价的
import (
    "a/b"
    "a/c"
)
例如需要调用a/b包中的函数test(),在代码中就可以这样写:b.test()

注意:

  • 导入包时禁止循环依赖,例如a依赖于b,而b又依赖于a,这是不允许的。
  • 如果要导入多个代码包,那么代码包路径的最后一个目录名称不可以重复,否则编译时就会报重复定义的错误,这个是由于go语言包声明规则导致的。

但是这种情况go语言有个解决方法:就是在导入时给相应冲突包起个别名,如下

import (
    La  "logging"
    Lb  "test/logging"
)

这样在使用时直接使用别名(La和Lb)来代替相应导入包名就可以区分具体使用的是哪个包中的变量或者函数了。

  • 如果需要直接调用某个依赖包的程序,可以用"."来代替别名

import (
    .  "a/b"
    "c/d"
)

例如需要调用a/b包中的函数test(),在代码中直接调用test()函数即可,而不需要再加上"b."了

包初始化

在Go语言中无参数声明和结果声明并且名为init的函数【func init() {XXX}】专门负责代码包的初始化工作。

  • 包初始化函数会在main函数之前执行,并且只执行一次
  • 对于一个代码包来说,其中的所有全局变量的初始化都会在包初始化函数之前执行,避免在init函数中对某个变量赋值不成功的情况(即被相应变量的声明时赋的值覆盖)
  • 在同一个代码包中,可以存在多个代码包初始化函数 
  • 在同一个源码文件中也可以存在多个代码包初始化函数

注意:

  • go语言编译器不能保证同一个代码包中的多个代码包初始化函数的执行顺序,所以要么一个代码包中只写一个代码包初始化函数,要么使用并发模型来保证执行顺序
  • 被导入的代码包初始化函数总是会在导入它的那个代码包的初始化函数之前执行




遗留问题:

  • 源码文件中声明包名为main,但是又不包含main入口函数的源码文件,根据定义好像本章说的三种都不满足?
  • 在我现在看过的资料中都没有说明源码文件是否可以直接放在工作区的src目录下,而放在工作区的src目录下之后,包应该怎么声明?声明成main包?

后续研究好后再补充,各位大牛如果看到也可解惑一二,在此不胜感激。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值