在一个语句中执行映射查找和类型声明是“坏形式”吗?

I just realized that it's possible to do a map lookup and a type/interface-assertion in one statement.

m := map[string]interface{}{
    "key": "the value",
}
if value, ok := m["key"].(string); ok {
    fmt.Printf("value exists and is a string: %s
", value)
} else {
    fmt.Println("value does not exist or is not a string")
}

Is this considered bad? I've not seen any official documentation commenting this.

edit: I know this code can not distinguish between "key doesn't exist" and "value is of incorrect type".

edit2: ahem, the print in the else-clause was incorrect :(

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
", k, value)
    } else {
        fmt.Printf("[key: %s] value does not exist or is not a string: %s
",
            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.

Is this considered bad?

No, this is plain wrong. You cannot combine map lookup and type assertion like this.

What you code does is:

  1. It looks up "key" in the map unconditional. If "key" is not in the map it will yield nil (as this is the zero value of interface{}).

  2. The value retrieved from the map (possible nil if not in the map is type asserted to a string.

Your code is incapable to determine whether "key" is in the map or not.