Go 为什么不支持从 main 包中导入函数?
创始人
2025-07-14 02:10:40
0

大家好,我是煎鱼。

作为一个维护过许多有一定历史沉淀的 Go 项目的人,在历史债务下和奇葩需求下,会遇到一些迫于业务需求的技术诉求。

诉求上是希望引用多项目,会出现从 main 包(package)中导入相关函数的这种使用诉求。为了将多 Go 工程合并到一个大单体中使用。

问题案例

具体的使用案例如下。

我们有一个 Go 应用,目录结构如下:

demo1
├── go.mod
├── main.go
└── x
    └── main.go

demo1/x/main.go 文件内代码如下:

package main

import (
 "fmt"
)

func main() {
 Main()
}

func Main() {
 fmt.Println("煎鱼进水了?")
}

demo1/main.go 文件内代码如下:

package main

import (
 "fmt"

 xmain "example.com/greet/x"  // 也就是本应用,上面的 x
)

func main() {
 fmt.Println("脑子进煎鱼了!")
 xmain.Main()
}

简单来讲,就是 demo1 这个 Go 项目,拥有两个 main 包。根目录下的 main.go 文件内引用了 x/main.go 内的 Main 方法。

运行该程序,看看运行结果:

$ go run main.go
main.go:6:2: import "example.com/greet/x" is a program, not an importable package

会直接报错,提示 x 包下是一个程序,而不是一个可导入的包。

为什么不支持导入 main 包

这个问题稍微可以收敛一下,关键内容是:为什么不支持导入 main 包内的函数?明明 main 包也是一个 package,其个别函数也是大写开头,是允许对外导出的。

我首先翻阅了一下 Go 语言规范(spec),确实没有非常明确禁止该项行为。但又确实在我们日常使用和编译运行时,会被拒绝运行。提示前面的错误。

随后又查看了具体的代码提交和 CL,实际上在 13 年前。现任 Go 核心团度负责人 @rsc 是提交过相应 main 包支持的。

如下 CL 所示:

图片图片

2011 年(13 年前)的 CL 移除了原本语言规范中定义的 “程序中的其他包都不能命名为 main” 的要求,也就是可以满足前文问题和背景中提到的使用诉求。

看到这里有的同学就疑惑了。怎么 13 年后的现在,2024 年。又不行了呢?而且感觉是不行好久了。

因为在 2015 年时,现任 Go 核心团队成员 @ianlancetaylor,又又又改了,增加了非常明确的判断,直接限制了。

如下代码变更:

图片图片

比较有趣的是,@rsc 和 @ianlancetaylor 的变更都是针对同一个 issues #4210:《cmd/go: go build does not reject importing commands》。

怎么后面又变了呢?@ianlancetaylor 给出的明确答复和定义:

图片图片

CL 4126053(原先 @rsc 提交的那次)是对描述语言规范的修改。该语言允许导入名为 main 的包。例如:在为使用 main 包的命令中的函数编写单元测试时,就可以使用它。

但这里的问题是关于 Go 工具,而不是语言。问题是 go 工具是否应该允许软件包导入定义命令的包。普遍的共识是不应该。

所提及的 Go 工具,覆盖的范围是:cmd/go。包含了 go build 等相关命令。因此是在受限制范围的。

经过如此切分场景,就能知道为什么语言规范上没有明确禁止。但 Go 工具上又明确拒绝了。因为其对应覆盖了不同的使用场景。

不支持的原因,结合讨论来看。

普遍认为支持 main 包的导入,会造成更大的复杂度和不安全性。

像是在 main 函数在编写时,通常会假定自己拥有完全的控制权,因此多个 main 包内的函数引入,可能会造成在 init 函数的初始化顺序、全局变量的注册等,都会产生程序上的冲突。

总结

在本次对 Go 工具限制从 main 包中导入相关函数的缘由,我们做了详尽的了解和分析。虽然 Go 官方这样的方式可以一刀切的解决复杂度和安全性的问题。

但有历史沉淀、债务的情况下,对于需要维护多个 Go 工程项目,要交付不同种类的可组合项目的程序员来说。相当于磨灭了一条道路。还是比较尴尬的。

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
Windows恶意软件20年“... 在Windows的早期年代,病毒游走于系统之间,偶尔删除文件(但被删除的文件几乎都是可恢复的),并弹...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
着眼MAC地址,解救无法享受D... 在安装了DHCP服务器的局域网环境中,每一台工作站在上网之前,都要先从DHCP服务器那里享受到地址动...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...