22

I am unable to find any documentation regarding what the type of the return value is when attempting key into a map in which the key doesn't exist. From the Go bug tracker it appears to be a special 'no value'

I'm trying to compare two values using the eq function but it gives an error if the key doesn't exist

Example:

var themap := map[string]string{}  
var MyStruct := struct{MyMap map[string]string}{themap}

{{if eq .MyMap.KeyThatDoesntExist "mystring"}}
  {{.}}
{{end}

Results in error calling eq: invalid type for comparison

From this I assume that the nil value is not the empty string "" as it is in Go itself.

Is there a simple way to compare a potentially non-existent map value and another value?

icza
  • 389,944
  • 63
  • 907
  • 827
Sam
  • 1,564
  • 4
  • 23
  • 37

2 Answers2

30

Use the index function:

{{if eq (index .MyMap "KeyThatDoesntExist") "mystring"}}
  {{.}}
{{end}}

playground example

The index function returns the zero value for the map value type when the key is not in the map. The zero value for the map in the question is the empty string.

Andy
  • 17,423
  • 9
  • 52
  • 69
Charlie Tumahai
  • 113,709
  • 12
  • 249
  • 242
  • Also works on older versions of Go, unlike the solution using {{if}}/{{with}} – Alice Purcell Feb 14 '17 at 14:48
  • @MuffinTop I can understand moderation of Qs & As, but comments can be a bit more wide-ranging, can't they? – Randy L Jun 10 '20 at 15:25
  • Any luck getting this to work when the `KeyThatDoesntExist` might exist as boolean that could be `false`? Seems the `if index .MyMap "booleanValue"` will fail when the `booleanValue` is false. Do you know of a way to check the existence of the boolean value? – Michael Andrews Jan 28 '21 at 22:02
3

You can first check if the key is in the map, and only perform the comparison if it is. You can check with another {{if}} action or with the {{with}} action which also sets the pipeline.

Using {{with}}:

{{with .MyMap.KeyThatDoesntExist}}{{if eq . "mystring"}}Match{{end}}{{end}}

Using another {{if}}:

{{if .MyMap.KeyThatDoesntExist}}
    {{if eq .MyMap.KeyThatDoesntExist "mystring"}}Match{{end}}{{end}}

Note that you can add {{else}} branches to cover other cases. Full coverage with {{with}}:

{{with .MyMap.KeyThatDoesntExist}}
    {{if eq . "mystring"}}
        Match
    {{else}}
        No match
    {{end}}
{{else}}
    Key not found
{{end}}

Full coverage with {{if}}:

{{if .MyMap.KeyThatDoesntExist}}
    {{if eq .MyMap.KeyThatDoesntExist "mystring"}}
        Match
    {{else}}
        No match
    {{end}}
{{else}}
    Key not found
{{end}}

Note that in all of the full coverage variants if key exists but associated value is "", that will also result in "Key not found".

Try these on the Go Playground.

icza
  • 389,944
  • 63
  • 907
  • 827
  • 1
    Great answer, just want to point out a caveat I found. This does not work if the value to the key is an empty string. [GoPlay](https://play.golang.org/p/C7KRIjwkXAE) – Liam Kelly Feb 26 '18 at 02:05
  • @LiamKelly Yes, you're right, because the zero value for the value type is treated as a `false` condition. The same thing goes for the other (accepted) answer too. – icza Feb 26 '18 at 08:30