前言
在组织项目的过程中被坑了许久,为了日后更快从坑里爬出来,决定汇总一下今天学到的golang包、模块等结构的组织方式;
具体来说即为命名规范,包的组织,包的导入等方面;
命名规范
package
go代码中必然会存在一个关键字:package
package是一个包名的定义,比如我自己想写一个模块贡献给开源世界,源码必然放在一个go文件里面,现在我需要定义一个包名;- 假设这个包名叫superhero,现在可以
package superhero; - 我可以自行组织我的模块结构,我可以同时在两份不同的go源码中表明这两份源码是同一个包;
- 既然是同一个包,那么这两份源码之间的可见性,遵循Go的内部规范,也就是要保证我源码A可以用源码B的函数,那么要求该函数首字母大写;
这是package关键字的用处,但是package关键字的命名规范则是:
- 比如我的两份源码都放在目录:
cs/learn/superhero,我就可以认为我这个包就叫superhero;- 当然,我也可以使得这两份源码属于不同的包,但是这么做没有必要,规范性不足。
- 那么如上所述,我直接就
package superhero;
这就是package关键字的规范,但是记住,当后面接的是main时,具有唯一性,代表主程序的入口地址;
import
会在很多相关代码中看到形如:import "ch2/tempconv"的包导入;
显然很容易理解为一种相对路径,但是Go的内部规范不建议用相对路径,认为会增加软件管理的难度;
- go引入了
go.mod进行模块的管理,所有模块的组织都可以通过该文件来进行; 假设该文件的内容:1 2 3
module GoLearn go 1.21.4
module GoLearn这一行代码表明,go.mod文件所在目录下的所有包组成了一个模块,该模块名叫GoLearn,go 1.21.4则表明了使用的go版本; - 因此,
import "ch2/tempconv"表示的应该是,在ch2模块下的包tempconv;
官方同时留了一个临时方案,就是在go.mod中通过replace关键字来解决一些特殊需求下的相对路径导入的问题;
包的组织
Golang中所有模块的组织,管理都是通过go.mod文件来进行的;
仍然以举的例子superhero来说明,一般而言,一个模块下都会需要有一个go.mod;
- 注意,这是一个模块,而不是包,一个模块中可以包含多个包,而我们可以认为一个模块就是一个文件夹;
- 一个文件夹下可以有很多个子文件夹,可以对应理解为有很多个包。
- 命令
go mod init <Your Module Name>;go mod init GoLearn,会在执行该命令的文件夹处(一般可以立即为工作区)生成一份go.mod文件,该文件内容大致为:1 2 3
module GoLearn go 1.21.4
GoLearn即为模块名,可以理解为寻找包的一个入口;
到这里,我们的模块写好了。
- 假设目录结构是
├── moduledemo │ ├── moduledemo1.go │ └── moduledemo2.go └── superhero ├── superhero1.go └── superhero2.go - 现在我在我的工作区写了一份go源码
main.go,需要调用moduledemo以及superhero包,假设工作区对应的模块名为GoLearn;- 只需要如此
import,那么两个包就被导入main.go,接下来继续调用即可。1 2 3 4 5 6 7 8 9 10
package main import ( "GoLearn/moduledemo" "GoLearn/superhero" ) func main() { moduledemo.moduledemo_func() superhero.superhero_func() }
- 只需要如此
- 完成
包的导入
单独起一节是因为碰到了这么一个问题:
在
import中导入了一个模块之后,代码运行没问题,编译没问题,但是vscode提示” no required module provides package “ch2/tempconv” “
也就是在编译器层面我的包正常导入且没有任何问题,但是vscode提示问题;
直到最后在main.go目录下的go.mod文件中加入replace ch2/tempconv => "./ch2/tempconv"之后vscode也不报问题了;
- 猜想是因为
ch2/tempconv正好与main.go go.mod在同一个目录下,如果是需要返回到上一级目录去找模块估计编译运行都会出问题了,因为./一般可以默认,../则不是; - 我猜的;
其实只要按照Go官方推荐的方式进行包的组织与管理就好了。
2024年6月16日更新:在Golang中,如果一个文件名形式为:`XX_test.go`,那么这个包内的函数在外界引用时会提示未定义.....