如何在Go中实现宏?

23

我完成了一个使用C++编写的项目,其中我使用#define宏来为项目命名,在多个地方使用该名称。我不经常更改此名称,但有时可能需要更改此名称,然后我更改此宏并重新构建我的代码。现在我正在将此代码转换为Go。有人可以建议我如何在Go中实现此功能吗?我不想使用全局变量来实现此目的,因为我有很多这样的宏,我怀疑这会导致我的项目占用更多的CPU并影响性能。


6
Go语言没有原生的C风格宏。 - matthias krull
5
如果你使用常量,与使用宏相比实际上没有性能差异。编译器可以进行相同类型的优化。 - nemequ
2个回答

32

幸运的是,Go语言不支持宏。

在Go语言中,有两种方法可以实现其他编程语言中使用宏的功能:

  • 使用代码生成来进行元编程。
  • 使用“符号替换”在链接时实现“魔法变量/常量”。

看起来,你需要的是后者。

不幸的是,这个特性的帮助文档几乎无法发现,但它在输出中有所解释。

$ go tool link -help

摘自文档的相关部分:

-X definition

添加字符串值definition,格式为importpath.name=value

那么您可以按照以下步骤进行操作:

  1. 在任意包中定义一个字符串常量,您希望在构建时更改其值。

    例如,在包foo中,您定义了常量Bar

  2. 在编译时的链接阶段,您向go buildgo install命令传递一个特殊标志:

     $ go install -ldflags='-X foo.Bar="my super cool string"'
    
    作为结果,生成的二进制文件将在其“只读数据”段中将常量foo.Bar设置为值“my super cool string”,并且该值将被程序代码使用。有关-ldflags选项的更多信息,请参见go help build输出。

12
你能解释一下为什么 "幸运地",Go语言不支持宏吗 :/ - Jenil Mewada
4
仅仅因为一旦你使用宏,你就不再看到程序的真实代码——你看到的是编译器实际编译的内容。需要注意的是,当我说“宏”时,我指的是人们通常所理解的C语言中的 #ifdef-fery;而在某些编程语言,比如LISP中,“真正”的宏是一个更有趣/复杂的话题。每个跟C打过交道的人,肯定都不止一次地要运行编译器的特殊模式“将所有宏展开后所得到的内容进行输出”,以尝试理解到底发生了什么鬼东西。 - kostix
6
"这只是一个特性,而不是错误"是一个非常薄弱的说法。在许多语言中都存在宏,例如C、erlang等,远远超过了#ifdef代码块或常量的范围。参数化宏是减少代码重复和使代码更加清晰的极好工具,应该成为编译器中任何正常预处理器的一部分。我意识到这个问题已经有些过时了,但我希望事情已经发生了改变,但是初步的谷歌搜索告诉我还没有。" - mritalian
1
@mritalian,在我的评论中,我提到了LISP作为具有“真正”宏的PL的例子,所以是的,我知道它们确实存在。问题在于,大多数时候,当人们询问宏时,他们并不是指_那些_东西;相反,他们指的是仅存在于预处理运行期间的宏,编译器不知道它们的存在。我对C(和经典C ++)有合理的了解,就我而言,我不希望在Go中看到这样的功能。基本上,这就是我在我的答案中试图阐述的;-) - kostix
2
@kostix "一旦你使用宏,你就再也看不到程序的真实代码了。" 你不能用同样的话说垃圾收集器吗? - tedtanner
显示剩余4条评论

13

Go语言不支持
但是你可以在一个包内定义常量,并在需要引用的地方使用。

package constant
// constants.go file

const (
    ProjectName = "My Project"
    Title       = "Awesome Title"
)

并且在你的程序中

package main
import "<path to project>/constant" // replace the path to project with your path from GOPATH

func main() {
     fmt.Println(constant.ProjectName)
}

项目结构将是:

project
   |- constant
   |      |- constants.go
   |-main.go

3
他也希望在需要时更改该值,因此使用const会产生问题。 - Shiva Kishore
9
他希望在编译时而非运行时更改它们,就像C/C++中的宏一样。使用“var”只会增加不必要的开销。 - nemequ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接