I would like to create a constant map like the following:
const ( running = map[string]string{ "one": "ONE", "two": "TWO", } )
however whenever I do I get the following error:
const initializer map[string]string literal is not a constant
Why is this the case, why does Golang not treat them like any other variable?
golang doesn't allow const maps.
If you're looking for a quick answer: Go doesn't support const arrays. It also doesn't support constant maps, slices, or other complex types. From the official specification: There are boolean constants, rune constants, integer constants, floating-point constants, complex constants, and string constants.
No. Maps are reference by default.
To declare a constant and give it a name, the const keyword is used. Constants cannot be declared using the := syntax.
From https://golang.org/ref/spec#Constants:
A constant value is represented by a rune, integer, floating-point, imaginary, or string literal, an identifier denoting a constant, a constant expression, a conversion with a result that is a constant, or the result value of some built-in functions such as unsafe.Sizeof applied to any value, cap or len applied to some expressions, real and imag applied to a complex constant and complex applied to numeric constants.
tl;dr only numeric types, strings and bools can be constants, arrays, slices and maps aren't a numeric type.
My take on this is that this decision was purely pragmatic: Go is a very down-to-Earth language (as opposed to other — "more purist" — languages), and one interesting property of some real-world map implementations is that mere accessing them for reading might update their internal representation (!). Say, they might gather and store some statistic on their usage, or they might rebalance an underlying tree which holds the value buckets etc. Allowing a "const map" to exist would mean explicitly specifying a set of complicated constraints on it in the language spec — most possibly requiring implementations to have two map implementations.
You can also try looking at it from another angle: consider a string constant. Such thing might be easily embedded into the .rodata
section of the resulting binary and be actually represented by the address of that data in memory (well, strings in Go are more complicated but let's ignore that detail). That is, a constant string can be truly "static": it's just a series of static R/O bytes in memory — as simple as that. Conversely, a map is a highly complicated beast powered by an intricate machinery, and each map is a special complex object instantiated at runtime. That's why you cannot even just declare a map and use it: you must make()
it first—just like channels, and for the same reason.
Again, some hack could possibly be done to support constant maps. Say, an implementation could sort the keys of your map up front, serialize it (with values) into a contigous region of R/O data and then use binary search at runtime to look the values up. That would be woefully ineffective for large maps / certain key patterns but would supposedly work. Still, that would be a specialized map implementation completely different from the "normal" one. I think Go devs decided the tradeoff is not worth possible benefit.
Two followup notes:
As you can see, you can relatively easily emulate a readonly map: have a slice literal of some struct types embedding both keys and values, presorted on the keys, and wrap it in a function which performs a binary search on the key.
I prefer to consider Go's constants a bit like macros in a C-like languages: they are untyped and feel like being textual (they are not but I'm speaking about feeling after all) ;-)
Be sure to read this for a great overview.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With