171

I am trying to declare to constant in Go, but it is throwing an error. Could anyone please help me with the syntax of declaring a constant in Go?

This is my code:

const romanNumeralDict map[int]string = {
  1000: "M",
  900 : "CM",
  500 : "D",
  400 : "CD",
  100 : "C",
  90  : "XC",
  50  : "L",
  40  : "XL",
  10  : "X",
  9   : "IX",
  5   : "V",
  4   : "IV",
  1   : "I",
}

This is the error

# command-line-arguments
./Roman_Numerals.go:9: syntax error: unexpected {
030
  • 9,351
  • 10
  • 70
  • 110
samol
  • 16,486
  • 28
  • 78
  • 117
  • 2
    golang doesn't allow const maps. here is a good explanation why https://www.reddit.com/r/golang/comments/993ujz/why_is_not_possible_to_create_a_constant_map/ – Rahim Oct 10 '20 at 20:29

5 Answers5

213

Your syntax is incorrect. To make a literal map (as a pseudo-constant), you can do:

var romanNumeralDict = map[int]string{
  1000: "M",
  900 : "CM",
  500 : "D",
  400 : "CD",
  100 : "C",
  90  : "XC",
  50  : "L",
  40  : "XL",
  10  : "X",
  9   : "IX",
  5   : "V",
  4   : "IV",
  1   : "I",
}

Inside a func you can declare it like:

romanNumeralDict := map[int]string{
...

And in Go there is no such thing as a constant map. More information can be found here.

Try it out on the Go playground.

Robert P
  • 15,414
  • 9
  • 69
  • 111
squiguy
  • 30,745
  • 6
  • 53
  • 59
31

You can create constants in many different ways:

const myString = "hello"
const pi = 3.14 // untyped constant
const life int = 42 // typed constant (can use only with ints)

You can also create a enum constant:

const ( 
   First = 1
   Second = 2
   Third = 4
)

You can not create constants of maps, arrays and it is written in effective go:

Constants in Go are just that—constant. They are created at compile time, even when defined as locals in functions, and can only be numbers, characters (runes), strings or booleans. Because of the compile-time restriction, the expressions that define them must be constant expressions, evaluatable by the compiler. For instance, 1<<3 is a constant expression, while math.Sin(math.Pi/4) is not because the function call to math.Sin needs to happen at run time.

Salvador Dali
  • 199,541
  • 138
  • 677
  • 738
  • 1
    so it's more like a C++11 constexpr... why math.Sin is not a constexpr function, then! – Francesco Dondi Jun 21 '16 at 23:40
  • Your statements are correct, but the question was about creating a map that is constant. – jzer7 Nov 13 '16 at 17:36
  • 7
    @jzer7 can you explain me why my answer is irrelevant? He asked how to create something, I told him that this is not possible. Explained what is possible and gave a citation from the docs why exactly is it not possible to do what he wants. – Salvador Dali Nov 13 '16 at 22:16
16

You may emulate a map with a closure:

package main

import (
    "fmt"
)

// http://stackoverflow.com/a/27457144/10278

func romanNumeralDict() func(int) string {
    // innerMap is captured in the closure returned below
    innerMap := map[int]string{
        1000: "M",
        900:  "CM",
        500:  "D",
        400:  "CD",
        100:  "C",
        90:   "XC",
        50:   "L",
        40:   "XL",
        10:   "X",
        9:    "IX",
        5:    "V",
        4:    "IV",
        1:    "I",
    }

    return func(key int) string {
        return innerMap[key]
    }
}

func main() {
    fmt.Println(romanNumeralDict()(10))
    fmt.Println(romanNumeralDict()(100))

    dict := romanNumeralDict()
    fmt.Println(dict(400))
}

Try it on the Go playground

pestophagous
  • 3,919
  • 3
  • 34
  • 41
oleber
  • 1,037
  • 4
  • 12
  • 24
  • 4
    (TestMostSoldRecommender?) – twotwotwo Dec 13 '14 at 09:00
  • 1
    It is in fact a possible solution. However, since the author did not explain anything (and put everything inside a weirdly-named test case), the answer looks incorrect. The logic is: (1) Create an anonymous function (2) The anonymous function encapsulates the `map` (3) The anonymous function returns "a function that accepts an int and returns a string" (4) The returned function does the int -> string mapping by using the `map` (5) Execute the anonymous function immediately and assign the returned function to a variable. This variable could be used like a function, and the effect is like a map. – Siu Ching Pong -Asuka Kenji- Dec 09 '15 at 16:03
4

And as suggested above by Siu Ching Pong -Asuka Kenji with the function which in my opinion makes more sense and leaves you with the convenience of the map type without the function wrapper around:

   // romanNumeralDict returns map[int]string dictionary, since the return
       // value is always the same it gives the pseudo-constant output, which
       // can be referred to in the same map-alike fashion.
       var romanNumeralDict = func() map[int]string { return map[int]string {
            1000: "M",
            900:  "CM",
            500:  "D",
            400:  "CD",
            100:  "C",
            90:   "XC",
            50:   "L",
            40:   "XL",
            10:   "X",
            9:    "IX",
            5:    "V",
            4:    "IV",
            1:    "I",
          }
        }

        func printRoman(key int) {
          fmt.Println(romanNumeralDict()[key])
        }

        func printKeyN(key, n int) {
          fmt.Println(strings.Repeat(romanNumeralDict()[key], n))
        }

        func main() {
          printRoman(1000)
          printRoman(50)
          printKeyN(10, 3)
        }

Try this at play.golang.org.

Denis Volin
  • 166
  • 8
-4

As stated above to define a map as constant is not possible. But you can declare a global variable which is a struct that contains a map.

The Initialization would look like this:

var romanNumeralDict = struct {
    m map[int]string
}{m: map[int]string {
    1000: "M",
    900: "CM",
    //YOUR VALUES HERE
}}

func main() {
    d := 1000
    fmt.Printf("Value of Key (%d): %s", d, romanNumeralDict.m[1000])
}
inde
  • 9
  • 1