在初始化期间建立的Go常数

In my Go program, there are configuration values that I want to be constant for the duration of program execution, but that I want to be able to change at the deployment site. As far as I can tell, there's no way to achieve this with the const keyword, since (again, as far as I can tell) its value must be a constant specified at compile time. This means that the only way to achieve what I want would be to declare normal variables and initialize them during the package's init function. It's not that that won't work, but rather that there will now be nothing to prevent these pseudo-constant's values from changing.

My two questions are:

  1. Am I missing something about how const works?
  2. Assuming I'm not, what's the preferred way to handle this? A public function that returns a private variable that I never expose, never changing it? Just hoping people don't alter the variables, since they're really configuration settings?

Create a file "config.go" and create the vars you want to expose.

Don't export them (make them all lower case). Instead create public (upper case) funcs that give access to each item.

package config

var x = 10

func X() int {
   return x
}

When you want those variables you simply import ./config and use them in code as follows:

if config.X()

Obviously, you can set the variables in the package init.

The following code is almost the same as the second method of @Christopher, except that it is not a module, it located in the main package.

package main

import (
    "os"
)

type Config struct {
    debug                bool
    key                  string
    proxyNumber          int
}

func (c *Config) Debug() bool {
    return c.debug
}
func (c *Config) Key() string {
    return c.key
}
func (c *Config) ProxyNumber() int {
    return c.proxyNumber
}

const (
    CONFIG_NAME = "config.ini"
)

var config *Config

func init() {
    DefaultConfig()
    if Exists(CONFIG_NAME) {
        //try to save the config file
    }else {
        //try to load from the config file

    }
}

func DefaultConfig() {
    config = &Config{debug:true, key:"abcde",
        proxyNumber:5,
    }
}

//Exist: check the file exist
func Exists(path string) bool {
    _, err := os.Stat(path)
    if err == nil { return true }
    if os.IsNotExist(err) { return false }
    return false
}

you can use config to load and save the config file.

This is a very good question because it delves into what I suspect may be an omission from Go - immutable state.

From the language reference, "constant expressions may contain only constant operands and are evaluated at compile-time."

You cannot make vars constant, which is a shame. Joe's answer proposes encapsulation as a solution, which will work well - but it's verbose, tedious and might introduce errors.

By comparison, many impure functional languages combine mutable variables with single-assignment immutable values. For example, Scala has the keywords 'val' and 'var'; the meaning of Scala's 'var' is quite similar to Go's 'var'. Immutability is a useful tool in the toolbox because referentially-transparent side-effect-free functions can be written, alongside stateful mutable procedural code. Both have their place. Immutability is also an valuable tool for concurrency because there is no worry about possible race conditions if immutable values are shared between goroutines.

So in my opinion, amongst its many strengths, this is one of Go's shortcomings. It would presumably not be hard to support vals as well as vars, the difference being that the compiler checks that each val is assigned exactly once.

Until that feature is added, you have encapsulation as your only option.

You can do something like this:

package main

import (
    "fmt"
    "strconv"
)

var a string

func main() {
    myvar, err := strconv.Atoi(a)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(myvar)
}

and compile the program with

go build -ldflags '-X main.a 10' test.go

That way you can define a constant during compile time.

Just use standard go flags with iniflags. Standard go flags allow setting arbitrary config variables at program start via passing command-line flags, while iniflags "magically" add support for reading config variables from ini files.