go程序中同一个包下为什么会存在多个同名的函数或变量

目录

背景

一探究竟

增加构建约束 & 不同格式的构建约束


背景

首先,这种情况显然是不符合编译规则的,我们都知道在同一个包下出现两个同名的函数、变量、常量等会编译不通过,那么怎么还会有这种现象存在?

如下,源码中任意找一个有这种现象的包:

一探究竟

既然都是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.goxxx_arm64.goxxx_linux_arm64.go命名的文件用于实现平台特定的代码。

2,编译器自动认识以_系统/arch名称结尾的go文件。

3,编译时,GOOS GOARCH都可以在文件名上来做构建约束,go编译器会根据当前操作系统自动选择匹配的文件进行编译。

增加构建约束 & 不同格式的构建约束

例如,针对不同的系统、架构的代码文件做相同的事情,我们可以进行编译约束:

即,顶部增加如下格式的约束(不能漏掉注释):

//go:build arm64 && freebsd

如下格式仅针对特定操作系统:

//go:build freebsd

如下格式针对特定的多个系统均可:

//go:build aix || darwin || freebsd || linux

如下格式的文件支持在linux系统、但不能在armarm64架构下进行编译

//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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ProblemTerminator

您的鼓励将是作者最大的动力哦!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值