在Go语言中,如何为开发环境和生产环境设置不同的常量值?

4
例如,我正在开发留言簿。它允许添加记录,需要由管理员批准。但是,在开发进一步功能时,批准每个在测试期间添加的记录是很麻烦的。 那么,有没有可能构建应用程序的dev版本,以创建具有适当标志设置的这些记录呢? 例如,prod build编译了以下函数:
func NewRecord() Record {
    return Record{Moderation: Awaiting}
}

在开发版本中,编译使用以下方法:

func NewRecord() Record {
    return Record{Moderation: Approved}
}

我知道在前端开发中,当你构建一些JS应用时,设置NODE_ENV=production环境变量是生产环境常见的做法。 我正在寻找Go语言中类似的方法。 我看到两种方式,但都不喜欢:

  1. I can just set Awaiting = Approved while developing and then change it back to actual value when building prod version. But I afraid that one day I will forget about this mock, will commit it to repo or something like that.
  2. Change function to something like

    func NewRecord() Record {
        if os.Getenv(mykey) == "production" {
                return Record{Moderation: Awaiting}
        } else {
                return Record{Moderation: Approved}
        }
    }
    

    But I don't like that this condition is evaluated in runtime for each new record. It just seems to be wrong for compiled language.

作为额外的福利,如果这样的应用程序可以在作为开发版本构建时显示警告(到stdout / stderr),那就太好了。
谢谢。
2个回答

7
个人认为像您在示例中所做的那样使用环境变量是做这件事的“正确”方式。这使您可以在不重新构建应用程序的情况下调整行为,这在调试时可能非常有用。但是,如果您真的想在编译时完成此操作,可以使用构建约束来实现。
构建约束是放置在文件顶部的特殊注释,表示“仅在满足特定条件时构建此文件”。条件可以是我们正在构建的机器架构、我们正在运行的操作系统或用户在构建时指定的自定义构建标记等。
例如,您可以将函数调整为以下内容:
func NewRecord() Record {
    return Record{Moderation: ModLevel}
}

然后定义ModLevel两次,一次在文件modlevel_prod.go中,看起来像这样(请注意,构建约束的语法正在更改,第二行是新语法,第一行不久将无效。有关更多信息,请参见本帖子末尾的链接):

// +build !dev
//go:build !dev

package mypackage

const ModLevel = Awaiting

还有一个在modlevel_dev.go中(或者其他地方,在这种情况下文件名并不重要)看起来像这样:

// +build dev
//go:build dev

package mypackage

const ModLevel = Approved

现在,在构建时,文件的生产版本是默认版本,如果想要构建文件的开发版本,则必须显式地包含构建标签:
$ go build -tags dev
< p > < em >编辑:构建约束的语法正在改变。我已经更新了示例,包括旧版本和新版本(目前并存)。有关更多信息和淘汰旧版本的时间表,请参见https://golang.org/issues/41184


谢谢!关于“正确性”,我还没有陈旧的观点。也许你是对的。 - user6743038
虽然这个答案回答了所提出的问题,但我支持@mellow-marmot的观点:这些东西应该是可配置的 - 也就是说,在启动时从某个配置文件和/或环境中提取。 - kostix

3

包初始化时对表达式进行一次评估:

var defaultModeration int

func init() {
    if os.Getenv(mykey) == "production" {
        defaultModeration = Awaiting
    } else {
        defaultModeration = Approved
    }
}

func NewRecord() Record { return Record{Moderation: defaultModeration} }

谢谢。实际上,我会使用这种方法,但是标记的答案描述了如何在提问时实现我想要的内容。 - user6743038
我唯一挑剔的评论是:永远不要使用init或包级别作用域来处理可变变量。这会在以后给你带来麻烦。在main函数(或其他地方)中初始化它,并将其传递到需要它的地方。 - user1087001

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