Creating a Static/hardcoded auto generated key val pair aka maps?

Porting a a application from python to go. I need to parse .h headers and auto generate key:val pairs or dicts known as maps in golang. But these need to be static since the code that generates the key:val pairs runs only once . The python implementation of this code simply creates a .py file that has defined dict with they key’s/vals in it.

What would be a similar implementation in go using maps ? or simply creating a json file would be smoother.

Basically is it possible to do hard coded maps in golang ?

edit : so what i have thought off is use init() to initialize the autogenerated hardcoded map everytime. my program runs.

Can you clarify what you mean by “static”?

If you’re looking for immutable key value pairs hard-coded into your program, then I think you want consts. They’re limited, though, you can only have scalar values like bool, int, float32, string, etc. No slices, structures, arrays, etc.

If your values are more than simple strings or numbers and/or by “static” you mean the C-like concept of static functions, variables, etc., then maybe global variables are what you want. In this case, the first step (though you might be able to do this in a single pass) would be to emit struct definitions from the data, then define one or more global variables that hold the values.

Based on your edit, it sounds like you just want a global map with all of the values. That might work for you, too.

Thank you for your reply skillian basically yup a global map with values. like in the pic below so basically a generated go file with hard values with init in my main func should work.

something like the pic below

@Pac23, there are a few ways you could do this, but the best way depends on how you use these values. The simplest may be to define two maps and initialize them the same way you’re initializing them in Python:

var byName = map[string]int{}
var byVal = map[int]string{}

func init() {
    byName["IDS"] = 1413685296
    byVal[1413685296] = "IDS"
    byName["IRMAP_CACHE"] = 1459634265
    byVal[1459634265] = "IRMAP_CACHE"
    byName["FS"] = 1363163410
    byVal[1363163410] = "FS"
    // ...
}

But I’d have other suggestions depending on how these values are used. If you frequently need to lookup these values by their names and the names are referenced elsewhere in the code, it makes sense to turn them into identifiers in the code.

That is, if you are currently doing stuff like this:

resource = acquire_resource(by_name["FS"])

In Go, it’d be better to turn these names into identifiers so you can catch errors like typos at compile-time, before your code is even tested.

If this is true, I’d recommend more abstraction like this:

package main

import (
	"fmt"
)

// nameValues is the global collection of NameValuePairs.
var (
	nameValues  = NewNameValues(1024)
	IDS         = nameValues.mustDefine(NameValuePair{Name: "IDS", Value: 1413685296})
	IRMAP_CACHE = nameValues.mustDefine(NameValuePair{Name: "IRMAP_CACHE", Value: 1459634265})
	FS          = nameValues.mustDefine(NameValuePair{Name: "FS", Value: 1363163410})
	// ...
)

// NameValuePair pairs together a Name and an integer value.
type NameValuePair struct {
	Name  string
	Value int
}

// NameValues is a collection of NameValuePairs indexed by both
// name and value.
type NameValues struct {
	// pairs is the actual collection of all of the name value pairs
	pairs []NameValuePair

	// names is a map of names to the index of the NameValuePair in
	// the pairs slice.
	names map[string]int

	// values is a map of values to the index of the NameValuePair in
	// the pairs slice.
	values map[int]int
}

// NewNameValues creates a new NameValues collection.
func NewNameValues(capacity int) *NameValues {
	return &NameValues{
		pairs:  make([]NameValuePair, 0, capacity),
		names:  make(map[string]int, capacity),
		values: make(map[int]int, capacity),
	}
}

func (nvs *NameValues) mustDefine(p NameValuePair) NameValuePair {
	added := nvs.Add(p)
	if !added {
		panic("redefinition of pair name or value")
	}
	return p
}

// Add a NameValuePair to the collection if it doesn't conflict with an
// existing entry's name or value.
func (nvs *NameValues) Add(p NameValuePair) (added bool) {
	i, ok := nvs.values[p.Value]
	if ok {
		return false
	}
	i, ok = nvs.names[p.Name]
	if ok {
		return false
	}
	i = len(nvs.pairs)
	nvs.pairs = append(nvs.pairs, p)
	nvs.names[p.Name] = i
	nvs.values[p.Value] = i
	return true
}

// ByName gets a NameValuePair by its name if it exists in the
// collection.
func (nvs *NameValues) ByName(name string) (NameValuePair, bool) {
	i, ok := nvs.names[name]
	if !ok {
		return NameValuePair{}, false
	}
	return nvs.pairs[i], true
}

// ByValue gets a NameValuePair by its name if it exists in the
// collection.
func (nvs *NameValues) ByValue(value int) (NameValuePair, bool) {
	i, ok := nvs.values[value]
	if !ok {
		return NameValuePair{}, false
	}
	return nvs.pairs[i], true
}

func main() {
	fmt.Println("IDS:", IDS.Value)
	fmt.Println("1459634265:", IRMAP_CACHE.Name)
}

This still assumes that the identifiers don’t change throughout the runtime of the program. If the identifiers are dynamic and you need to access them by strings, it is probably good enough to use the two-map approach instead.

1 Like

Thank you for the detailed reply,two map approach is smart af.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.