go程序中同一个包下为什么会存在多个同名的函数或变量(详细解析)
作者:ProblemTerminator
背景
首先,这种情况显然是不符合编译规则的,我们都知道在同一个包下出现两个同名的函数、变量、常量等会编译不通过,那么怎么还会有这种现象存在?
如下,源码中任意找一个有这种现象的包:
一探究竟
既然都是go代码,肯定是适配同一套逻辑的。
创建一个测试项目,创建一个包pkg,分别创建如下文件:
我们让mypkg包下的所有文件中都有GetPackageName函数(返回的值不同)、flag变量。
注意,这些文件目前并未提示redeclared。
然后main中调用GetPackageName函数。
在运行之前,编译器并没有显式的报错。接着go build,编译正常。运行结果输出了:
mypkg from windows
交叉编译一下Linux平台,运行:
mypkg from linux
看起来编译时自动找到对应文件处理了。
继续。
在mypkg包下接着新建一个名为openbsd.go的文件,和上述文件的函数保持同名,然后很明显的报错出来了:'GetPackageName' redeclared in this package
条件不变,且在pkg_windows.go文件已存在的前提下:
继续创建名为_openbsd.go的文件,没有报错。
继续创建名为pkg_amd64.go、pkg_x64.go、pkg_x86.go、othername_amd64.go等文件均会提示redeclared。
但创建的othername_arm64.go、pkg_linux_amd64.go、pkg_linux_arm64.go不会提示。
对于linux的两个文件,这里看着没毛病,实际上在linux、amd64平台上编译就会报错:
mypkg\pkg_linux_amd64.go:4:2: flag redeclared in this block
mypkg\pkg_linux.go:4:2: other declaration of flag
mypkg\pkg_linux_amd64.go:7:6: GetPackageName redeclared in this block
mypkg\pkg_linux.go:7:6: other declaration of GetPackageName
是因为pkg_linux_amd64.go文件和pkg_linux.go文件的同名内容冲突了,在linux、amd64平台上编译,这两文件就会被适配到。
如果目标平台改为linux、arm64进行编译,也会报:
mypkg\pkg_arm64.go:4:2: flag redeclared in this block
mypkg\othername_arm64.go:4:2: other declaration of flag
mypkg\pkg_arm64.go:7:6: GetPackageName redeclared in this block
mypkg\othername_arm64.go:7:6: other declaration of GetPackageName
mypkg\pkg_linux.go:4:2: flag redeclared in this block
mypkg\othername_arm64.go:4:2: other declaration of flag
mypkg\pkg_linux.go:7:6: GetPackageName redeclared in this block
mypkg\othername_arm64.go:7:6: other declaration of GetPackageName
是因为othername_arm64.go文件、pkg_arm64.go和pkg_linux.go文件的同名内容冲突了,在linux、arm64平台上编译,这三个文件就会被适配到。
综合来看:
1,类似约定xxx_windows.go、xxx_arm64.go、xxx_linux_arm64.go命名的文件用于实现平台特定的代码。
2,编译器自动认识以_系统/arch名称结尾的go文件。
3,编译时,GOOS 和 GOARCH都可以在文件名上来做构建约束,go编译器会根据当前操作系统自动选择匹配的文件进行编译。
增加构建约束 & 不同格式的构建约束
例如,针对不同的系统、架构的代码文件做相同的事情,我们可以进行编译约束:
即,顶部增加如下格式的约束(不能漏掉注释):
//go:build arm64 && freebsd
如下格式仅针对特定操作系统:
//go:build freebsd
如下格式针对特定的多个系统均可:
//go:build aix || darwin || freebsd || linux
如下格式的文件支持在linux系统、但不能在arm或arm64架构下进行编译
//go:build linux && !arm && !arm64
感叹号表示“非”。
以上是go 1.17及以上版本引入的格式,定义了一个布尔表达式,包含了逻辑运算符,条件可以更复杂。
与此不同,下面的格式是go 1.17以下支持的约束格式:
// +build freebsd
也会有两种格式并存的情况:
//go:build linux // +build linux
因为也有环境是老编译器的情况,老版本的编译器不能识别新的约束语法。
go语言支持的系统和架构列表
#go tool dist list aix/ppc64 android/386 android/amd64 android/arm android/arm64 darwin/amd64 darwin/arm64 dragonfly/amd64 freebsd/386 freebsd/amd64 freebsd/arm freebsd/arm64 freebsd/riscv64 illumos/amd64 ios/amd64 ios/arm64 js/wasm linux/386 linux/amd64 linux/arm linux/arm64 linux/loong64 linux/mips linux/mips64 linux/mips64le linux/mipsle linux/ppc64 linux/ppc64le linux/riscv64 linux/s390x netbsd/386 netbsd/amd64 netbsd/arm netbsd/arm64 openbsd/386 openbsd/amd64 openbsd/arm openbsd/arm64 openbsd/ppc64 plan9/386 plan9/amd64 plan9/arm solaris/amd64 wasip1/wasm windows/386 windows/amd64 windows/arm windows/arm64
到此这篇关于go程序中同一个包下为什么会存在多个同名的函数或变量的文章就介绍到这了,更多相关go程序同一个包存在多个同名的函数或变量内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!