Go语言中的模块是让一些相同业务的功能集合在一个目录,方便被其他业务调用,独立性强,耦合低,方便维护。Go语言零基础入门,从安装到运行代码 在这篇文章也有示例,但只说了一种生成go.mod的方式来调用的方法,尤其对于同级目录的go文件的调用,有坑在里面。
先查看下自己的go的环境,命令行输入: go env
如果列表中发现是关闭的
set GO111MODULE=off
我们将其打开:
go env -w GO111MODULE=on
其余的环境变量,大家都可以去了解,最关键的是安装目录GOROOT与工作目录GOPATH。
准备工作:新建一个工作目录mywork,在下面新建两个目录,testa和testb目录,再分别在其下面新建两个go文件:testa.go和testb.go,现在的目的是testa调用testb中的函数,以下是cmd命令行操作:
- REM:进入目录testb,生成一个模块文件go.mod,使用域名是为了让模块名称唯一:tony.com/testb,虽然可以使用别名,但不是一种良好的编码规范
-
- cd testb
- go mod init tony.com/testb
- REM:进入目录testa,生成一个模块文件go.mod,模块名称指向其所在位置,最后使用tidy整理模块即可
-
- cd testa
- go mod init tony.com/testa
- go mod edit -replace tony.com/testb=../testb
- go mod tidy
调用的时候,就是导入上面生成的模块名:import "tony.com/testb",然后使用testb调用里面的函数即可
- C:\Users\Tony\go\src\mywork\testa>go run testa.go
- /*
- 和的结果: 7
- 你好,寅恪光潜,近来可好?
- */
testa.go
- package main
-
- import (
- "fmt"
- "tony.com/testb"
- )
-
- func main() {
- fmt.Println("和的结果:", testb.Sum(3, 4))
- fmt.Println(testb.Hello("寅恪光潜"))
- }
testb.go
- package testb
-
- import "fmt"
-
- func Sum(i1 int, i2 int) int {
- return i1 + i2
- }
-
- func Hello(s string) string {
- res := fmt.Sprintf("你好,%s,近来可好?", s)
- return res
- }
如果是开启的,我们将它设置成关闭模块模式,运行看下效果go run testa.go
go env -w GO111MODULE=off
testa.go:6:2: cannot find package "tony.com/testb" in any of:
D:\Program Files\Go\src\tony.com\testb (from $GOROOT)
C:\Users\Tony\go\src\tony.com\testb (from $GOPATH)
错误提示:我们发现找不到包了,在安装目录与工作目录都没有找到。
这个是肯定的,因为不是go.mo模块模式了,而是会在去寻找实际的本地目录,所以我们将这个模块的名称修改成本地目录即可,根目录是mywork,因为是存放在GOPATH的src目录下面
import "mywork/testb"
- C:\Users\Tony\go\src\mywork\testa>go run testa.go
- /*
- 和的结果: 7
- 你好,寅恪光潜,近来可好?
- 当然前提条件是需要放在工作目录的src里面
- */
那如果同一目录下面的go文件怎么去调用呢。比如在testa目录新建一个testaa.go文件,然后调用这个新建文件里面的函数:
testaa.go
- //package testaa
- package main
-
- func Sub(i1 int, i2 int) int {
- return i1 - i2
- }
我们来调用试下:
- package main
- import "mywork/testa/testaa"
- func main() {
- fmt.Println(testaa.Sub(5, 2))
- }
C:\Users\Tony\go\src\mywork\testa>go r un testa.go
testa.go:7:2: cannot find package "mywork/testa/testaa" in any of:
D:\Program Files\Go\src\mywork\testa\testaa (from $GOROOT)
C:\Users\Tony\go\src\mywork\testa\testaa (from $GOPATH)
我们发现找不到这个testaa包名,但实际上在这个目录下面是有这样的包名存在的啊。为什么?
首先这个testaa包名是一个目录,这里不是目录,是文件,另外就是同级目录不需要加载模块,只需要编译即可,然后调用的时候也是直接使用方法名调用,这是关键点,因为上面go run testa.go,没有编译testaa.go文件,所以出现找不到包或者是方法未定义等其他错误。
我们来到testa目录,然后编译里面的文件,这样就可以直接调用了,如下:
C:\Users\Tony\go\src\mywork\testa>go build
这样就在当前目录下面编译成了一个testa.exe文件,我们运行看下:
- C:\Users\Tony\go\src\mywork\testa>testa
- /*
- 和的结果: 7
- 你好,寅恪光潜,近来可好?
- 3
- */
源码如下,其中调用的时候直接Sub,不需要前面加包名来引用。
- package main
-
- import (
- "fmt"
- "mywork/testb"
- )
-
- func main() {
- fmt.Println("和的结果:", testb.Sum(3, 4))
- fmt.Println(testb.Hello("寅恪光潜"))
- fmt.Println(Sub(5, 2))
- }
-
根据上面的方法,现在我们在testb里面新增一个testbb.go文件,然后testb去调用testbb,最后在testa中调用他们,会处理吗?
testb.go
- package testb
-
- import "fmt"
-
- func Sum(i1 int, i2 int) int {
- return i1 + i2
- }
-
- func Hello(s string) string {
- res := fmt.Sprintf("你好,%s,近来可好?", s)
- res1 := HelloBB("法外狂徒张三")
- return res + res1
- }
testbb.go
- package testb
-
- import "fmt"
-
- func HelloBB(s string) string {
- res := fmt.Sprintf("Hello %s", s)
- return res
- }
细心的伙伴们可能发现,同级目录的包名package要一样,不然编译会出错,比如testb下面所有的go文件的统一包名为package testb,然后我们将testb下面所有文件的编译,再编译testa所有文件,最后就会生成一个testa.exe,从这里也可以得出,后期同级目录下面的go文件的package名称统一是目录名称即可。
- C:\Users\Tony\go\src\mywork\testb>go build
-
- C:\Users\Tony\go\src\mywork\testb>cd ../testa
-
- C:\Users\Tony\go\src\mywork\testa>go build
-
- C:\Users\Tony\go\src\mywork\testa>testa
-
- /*
- 和的结果: 7
- 你好,寅恪光潜,近来可好?Hello 法外狂徒张三
- 3
- */