Go中如何从子模块调用主模块的函数?
Go工作区中主模块与db子模块的调用问题
问题场景与尝试
我有一个主模块和子模块db,初始go.work配置如下:
go 1.19 use ./ use ./db
我希望在db模块中直接调用主模块的函数,尝试编写如下代码:
package db import "main" func DatabaseCall() { main.FooBar("lorem") }
之后我调整了go.work的结构:
go 1.19 use ./main use ./db
但仍然无法实现调用。想知道是main包有特殊限制,还是操作有误?
我曾通过传递函数回调的方式实现需求,代码如下:
// db模块代码 type FooBar func(ipsum string) func DatabaseCall(handler FooBar) { handler("lorem") } // main模块代码 db.DatabaseCall(FooBar)
但我担心这种方式会导致整个函数在内存中被复制,不是我想要的结果;即使传递指针,调用前解引用也会产生复制。
解答
1. main包的核心限制
Go语言中main包是特殊的,禁止被其他任何包导入,这是语言层面的硬性规则,和go.work的配置无关。main包的设计定位是程序的入口,编译器会将其编译为可执行文件,而非可复用的库,因此其他模块无法通过导入main来调用其中的函数。
2. 函数传递的性能误区
你担心的「函数被复制」是误解:
- Go中的函数类型本质是函数指针,传递函数值时,复制的只是这个指针(占用少量内存,通常是8字节),而非函数的代码段。函数代码在编译后会被放在只读内存区域,不会被复制。
- 不需要额外传递函数指针,因为函数值本身就相当于对函数代码的引用,直接传递函数名即可(如你代码中的
db.DatabaseCall(FooBar)),不存在额外的性能开销。
3. 可行的替代方案
方案1:抽离公共模块
将需要被main和db共同调用的函数,抽离到一个独立的库模块(比如./common),调整go.work:
go 1.19 use ./main use ./db use ./common
然后在main和db模块中分别导入common,db就可以直接调用common中的函数,避免依赖main包。
方案2:保留回调模式
既然回调模式本身没有性能问题,完全可以继续使用。这种方式还能让db模块更灵活,不依赖特定的实现逻辑,符合依赖倒置原则。
内容的提问来源于stack exchange,提问作者10Nates
相关产品推荐
相关产品推荐

