What you do actually works, because you use the special comma-ok idiom of the type assertion which does not panic if the assertion does not hold, and because maps can be indexed with keys which are not in it (which will result in the zero value of the value type of the map).
It's true that with this you can't tell if the key is in the map or not, or it is but its value is nil
, but you already suspected this as if the assertion does not hold, you print "value does not exist or is not a string".
To test all "corner" cases, see this example:
m := map[string]interface{}{
"key": "the value",
"key2": 2,
"key3": nil,
// "key4":"", // Uncommented on purpose
}
for _, k := range []string{"key", "key2", "key3", "key4"} {
if value, ok := m[k].(string); ok {
fmt.Printf("[key: %s] value exists and is a string: %s\n", k, value)
} else {
fmt.Printf("[key: %s] value does not exist or is not a string: %s\n",
k, value)
}
}
Output (try it on the Go Playground):
[key: key] value exists and is a string: the value
[key: key2] value does not exist or is not a string:
[key: key3] value does not exist or is not a string:
[key: key4] value does not exist or is not a string:
So basically you can use this, nothing bad will happen from it (e.g. panic or memory leak), just know its limits (e.g. you couldn't get the value associated for "key2"
as it's not of string
type).
If your intention is to get the value for a key if it exists and is of type string
, then this is what your code exactly does. Although you should avoid data structures and constructs where you need this, as it's harder to understand and maintain in larger projects.
What I mean by this is for example if at some point in your code you expect the key "somekey"
to have a string
value associated and it does not, you won't immediately know why it is so; is it because the map does not contain that key, or is it because it does but with a value of wrong type (or the value may even be nil
)? Further testing / debugging is needed to track down the root cause.