46

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?

STF
  • 1,485
  • 3
  • 19
  • 36
anonrose
  • 1,271
  • 3
  • 12
  • 19
  • 2
    I think that the answer to the question **why** is that the authors of go judged that the complexity of the implementation is not worth the benefits it brings. – ain Jun 23 '16 at 07:31
  • 4
    Possible duplicate of [declare a constant array](http://stackoverflow.com/questions/13137463/declare-a-constant-array) – icza Jun 23 '16 at 07:33
  • I think that you possible want an immutable map. You cannot declare an immutable map only because a map in Go language is a language construction but not a implementation of some `Map` interface. That is, you cannot implement your own map which are compatible (by the interfaces) with the internal Go map. – mezoni Jun 23 '16 at 11:11

2 Answers2

37

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.

OneOfOne
  • 95,033
  • 20
  • 184
  • 185
  • 2
    Also, functions cannot be declared as constants. – Lucio Mollinedo Dec 27 '19 at 03:35
  • Coming across this question years later, but this isn't really an answer so much as a tautology: maps can't be constant because they aren't one of the types Go allows to be constant. The important and interesting part is why the language wasn't or couldn't be designed that way, to which [kostix offers some possible explanations](https://stackoverflow.com/a/38001136/3403230). – GregWW Dec 01 '22 at 16:26
8

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.

kostix
  • 51,517
  • 14
  • 93
  • 176