One way to do it is to create your own map[string]string type and add some simple methods to that. Here is a simple example:
type mapExists map[string]string func (m mapExists) exists(key string) bool { _, ok := m[key] return ok } func (m mapExists) isInt(key string) bool { v, ok := m[key] if !ok { return false } _, err := strconv.ParseInt(v, 10, 64) return err == nil }
You can convert a map[string]string to the mapExists with:
m := map[string]string{ "a": "b", "c": "2", } m2 := mapExists(m)
And then call stuff like in your example:
fmt.Println("a exists:\t", m2.exists("a")) fmt.Println("asd exists:\t", m2.exists("asd")) fmt.Println("a isInt:\t", m2.isInt("a")) fmt.Println("c isInt:\t", m2.isInt("c"))
Which will output:
a exists: true asd exists: false a isInt: false c isInt: true
Whether this is the "best" or "idiomatic" way is a matter of opinion and depends on the circumstances. In general, I would (personally) prefer to not use these wrappers. Your above example could be rewritten to something like the following :
func test() { m := map[string]string{"a": "b", "c": "d", "e": "f"} v1, v1ok := m["a"] v2, v2ok := m["c"] if !v1ok || !v2ok { return } i1, err := strconv.Atoi(v1) if err != nil { return } i2, err := strconv.Atoi(v2) { if err != nil { return } }
Which I think is much more readable. It's more verbose, but Go is a verbose language ;-)
But again, it depends on the entirety of your codebase. If you're calling this pattern very often then a custom type might be a good solution (at the cost of slightly lower performance, which may or may not be a problem).