01 包的基本概念

【其中S表示原文,A表示我的个人解释】

【请注意,这里面充满大量不成熟的、主观推测的看法】

【大家可以去B站关注七米老师,里面都是很不错的内容】

S1:Go语言中支持模块化的开发理念,在Go语言中使用包(package)来支持代码模块化和代码复用。一个包是由一个或多个Go源码文件(.go结尾的文件)组成。

A1:Go语言它使用包(package)这一组织单元来组织代码以提供代码复用和模块化。一个包由一个或多个go源代码文件组成,源代码文件是Go语言的最小使用单元。在Go语言中,一个包实质上对应于文件系统中的一个目录(文件夹)。该目录下包含一个或多个.go源文件,这些文件共同组成了这个包。每个.go文件的开头通过package关键字声明其所属的包名,确保了文件间的归属和逻辑组织。当一个包只包含一个.go文件时,这个文件即代表了整个包的内容,但从组织结构上看,它依然遵循“包即目录”的原则。但如果不定义包目录,直接用一个文件,也就是取消包目录,直接使用源文件(前提是该包只有这么一个文件),也是可行的,但是在实际的工程中并不推荐如此,因为不便管理。

S2:在同一个包内部声明的标识符都位于同一个命名空间下,在不同的包内部声明的标识符就属于不同的命名空间。想要在包的外部使用包内部的标识符就需要添加包名前缀。

A2:也就是说包下的每个文件因为有了包的标记而获得独特性,即便是两份同名为a.go的文件,也会因为一个属于b包,一个属于c包,而被标记为b/a.go和c/a.go,这让它的全称是不同的,这表明,即使相对路径下的文件名相同,包名的加入使得它们在编译器眼中具有了独一无二的身份,这通过包名的前缀在编译器层面实现了标识符的唯一性,使用包内部的标识需要添加包名前缀就体现了这一点。因此,包名的不同不仅是逻辑上的组织手段,也是实现文件和标识符区分的关键机制。因此这里的独特性只在全称路径上,而在相对路径上它们的名字是一致的。包只要保证自己与其他包的区别,就可以保证其下属文件的不同。而且从物理存储的角度,每个包可以看作是一个独立的存储区域,不同的包实际上在文件系统中对应不同的目录,即使文件名相同,由于位于不同的目录(包)下,它们在磁盘上占据的也是不同的物理位置。包不仅是一种物理上的文件组织方式,更重要的是它提供了一种逻辑上的抽象层次,使得开发者能够按照功能、模块或者职责来划分代码,从而使得项目结构清晰,易于理解和维护。每个包的定义都是对项目逻辑结构的一次明确划分,确保了代码的模块化和可复用性。

S3:在Go语言中是通过标识符的首字母大/小写来控制标识符的对外可见(public)/不可见(private)的。在一个包内部只有首字母大写的标识符才是对外可见的。

A3:也就是说,Go语言中在包的层面上,所有包内文件之间的信息是共享的,源文件并不能在文件的层次上控制自己内部标识符的可见性,这说明,在实际运行的层面上,包是基本的编译单元和封装边界。包内的所有源文件共享信息,并且共同构成了一个逻辑上的整体,它们之间不设立单独的可见性屏障。标识符的可见性规则(即首字母大写表示公有,小写表示私有)是在包的层面定义的,用于控制包与包之间的接口暴露,而不是用来限制同一个包内不同文件之间的访问权限。编译器只能感知到包这一级别,而忽略掉源文件这一级别。这表明,Go语言在设计上认为同一包内的代码应当紧密协作,不需要也不支持细粒度的文件级访问控制。

S4:

要在当前包中使用另外一个包的内容就需要使用import关键字引入这个包,并且import语句通常放在文件的开头,package声明语句的下方。完整的引入声明语句格式如下:

import importname "path/to/package"

其中:

  • importname:引入的包名,通常都省略。默认值为引入包的包名。
  • path/to/package:引入包的路径名称,必须使用双引号包裹起来。

A4:在Go语言中,路径可以是相对路径,但更常见的是使用标准库路径(无需前缀)或是绝对导入路径(通常以github.com/用户名/项目名/...等形式出现)。标准库的导入路径是预定义的,无需指定完整的URL或文件系统路径,编译器知道去哪里找它们,因为编译器知道fmt包位于Go的标准库路径中。而对于非标准库的包,Go语言在寻找这些包时会依据GOPATH、GOROOT等环境变量以及go mod 模块(如果启用了模块)来定位包的具体位置。如果没指定GOPATH或使用了go modules,Go会根据包名去GOPATH的src目录下找对应的子目录。启用go modules 后,模块的路径解析遵循go.mod文件的定义和go.sum的校验。

S5:一个包的初始化过程是按照代码中引入的顺序来进行的,所有在该包中声明的init函数都将被串行调用并且仅调用执行一次。每一个包初始化的时候都是先执行依赖的包中声明的init函数再执行当前包中声明的init函数。确保在程序的main函数开始执行时所有的依赖包都已初始化完成。

A5:我个人认为,其中关键点在于要“确保在程序的main函数开始执行时所有的依赖包都已初始化完成”,其在每一个包中时也可以视作要“确保在程序的init函数开始执行时所有的依赖包都已初始化完成”(这么说并不准确,因为init函数并不是每一个包都定义了,也就不是每一个包都要执行,没有定义init函数的包需要执行的是包级别的常量和变量),其中初始化包括的是“一个包中包级别的常量、变量的初始化,如有init函数,则init函数也要保证执行”。保证了程序在真正进入业务逻辑之前,所有必要的环境准备、资源加载、配置检查等工作都已完成,为后续的执行奠定了稳定的基础。Go语言通过精心设计的包初始化机制,确保了程序启动阶段的有序性和完整性,是其健壮性设计的重要组成部分。

  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值