如何在Go中实现宏?

Pav*_*ath 1 macros go

我用C++完成项目,我用#define宏来给出项目的名称,我在几个地方使用过,我不经常更改这个名称,但有时我可能需要更改它,然后我更改此宏并重建我的代码.现在我将此代码转换为Go.有人可以建议我如何在Go中实现这个?我对使用全局变量没有兴趣,因为我有很多这样的宏,我怀疑这会导致我的项目占用更多的CPU并影响性能.

kos*_*tix 14

幸运的是,Go不支持宏.

Go中有两个场所用于实现在其他编程语言中使用宏所做的事情:

  • "元编程"是使用代码生成完成的.
  • "魔术变量/常数"在链接时使用"符号替换"来实现.

看来,后者就是你所追求的.

不幸的是,这个功能的帮助本身几乎是不可发现的,但它在输出中解释了

$ go tool link -help
Run Code Online (Sandbox Code Playgroud)

引用它的相关位:

-X definition

添加definition表单的字符串值importpath.name=value

所以你像这样滚动:

  1. 在任何方便的包中,您可以定义一个字符串常量,您希望在运行时更改该值.

    比方说,你Bar在包中定义常量foo.

  2. 在构建时,您将传递go buildgo install调用链接阶段的特殊标志:

    $ go install -ldflags='-X foo.Bar="my super cool string"'
    
    Run Code Online (Sandbox Code Playgroud)

结果,生成的二进制文件将foo.Bar 在其"只读数据"段中将常量设置为值"my super cool string",该值将由程序的代码使用.

另请参阅go help build有关该-ldflags选项的输出.

  • “这是一个功能而不是一个错误”是一个非常弱的说法。宏存在于许多许多语言中,并且存在于 C 或 erlang 等语言中……远远超出了“#ifdef”代码块或常量的范围。参数化宏是减少代码重复并使事情看起来更干净的绝佳工具,并且应该成为编译器中任何普通预处理器的一部分。我意识到这个问题已经过时了,我祈祷从那时起事情已经发生了变化,但粗略的谷歌搜索告诉我没有。 (7认同)
  • 你能解释为什么“幸运地”Go 不支持宏:/ (3认同)
  • @JenilMewada,仅仅因为一旦你有了宏,你就不再看到程序的真实代码——你会从编译器实际编译的内容中看到其他东西。请注意,当我说“宏”时,我指的是人们倾向于通过该名称通俗地理解的内容——C 是 `#ifdef`-fery;在某些编程语言(如 LISP)中,“真正的”宏是一个更有趣/更复杂的话题。每个与 C 打交道的人,肯定不止一次必须在其特殊模式下运行编译器“转储扩展所有宏后得到的内容”,以试图了解到底发生了什么。 (3认同)
  • @kostix“一旦有了宏,您就不再看到程序的真实代码。” 你不能对垃圾收集器说同样的话吗? (3认同)

Shi*_*ore 9

Go不支持Macros.
但是您可以在包中使用常量并在需要的地方引用它.

package constant
// constants.go file

const (
    ProjectName = "My Project"
    Title       = "Awesome Title"
)
Run Code Online (Sandbox Code Playgroud)

在你的程序中

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

func main() {
     fmt.Println(constant.ProjectName)
}
Run Code Online (Sandbox Code Playgroud)

项目结构将是

project
   |- constant
   |      |- constants.go
   |-main.go
Run Code Online (Sandbox Code Playgroud)

  • 他想在编译时更改它们,而不是在运行时更改它们.就像C/C++中的宏一样.`var`只会增加不必要的开销. (6认同)
  • 他还希望在需要时更改值,因此使用 const 会产生问题。 (3认同)