是"bad form"在一条语句中执行映射查找和类型断言吗?
Is it "bad form" to perform map lookup and type assertion in one statement?
我刚刚意识到可以在一条语句中执行地图查找和 type/interface-assertion。
m := map[string]interface{}{
"key": "the value",
}
if value, ok := m["key"].(string); ok {
fmt.Printf("value exists and is a string: %s\n", value)
} else {
fmt.Println("value does not exist or is not a string")
}
这算不算坏事?
我还没有看到任何官方文档对此进行评论。
编辑:我知道这段代码无法区分 "key doesn't exist" 和 "value is of incorrect type"。
edit2:咳咳,else 子句中的打印不正确:(
Is this considered bad?
不,这是完全错误的。您不能像这样组合地图查找和类型断言。
您的代码所做的是:
在地图无条件中查找"key"。如果 "key" 不在映射中,它将产生 nil(因为这是 interface{} 的零值)。
从地图中检索到的值(如果不在地图中则可能为 nil 类型断言为字符串。
您的代码无法确定 "key" 是否在地图中。
你所做的实际上是有效的,因为你使用了 type assertion 的特殊 comma-ok 习惯用法,如果断言不成立,它不会恐慌,并且因为映射可以用不在它(这将导致映射值类型的零值)。
的确,用这个你不能判断键是否在映射中,或者它是但它的值是 nil
,但你已经怀疑这一点好像断言不成立, 你打印 "value does not exist or is not a string".
要测试所有 "corner" 个案例,请参阅此示例:
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)
}
}
输出(在 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:
所以基本上你可以使用它,它不会发生任何坏事(例如恐慌或内存泄漏),只需要知道它的限制(例如你无法获得关联的值对于 "key2"
因为它不是 string
类型)。
如果您的目的是获取键的值(如果它存在且类型为 string
),那么这正是您的代码所做的。尽管您应该避免在需要的地方使用数据结构和构造,因为在大型项目中更难理解和维护。
我的意思是,例如,如果在您的代码中的某个时刻,您希望键 "somekey"
具有关联的 string
值,但它没有,您不会立即知道为什么会这样;是因为地图不包含该键,还是因为它包含但具有错误类型的值(或者该值甚至可能是 nil
)?需要进一步测试/调试以追查根本原因。
我刚刚意识到可以在一条语句中执行地图查找和 type/interface-assertion。
m := map[string]interface{}{
"key": "the value",
}
if value, ok := m["key"].(string); ok {
fmt.Printf("value exists and is a string: %s\n", value)
} else {
fmt.Println("value does not exist or is not a string")
}
这算不算坏事? 我还没有看到任何官方文档对此进行评论。
编辑:我知道这段代码无法区分 "key doesn't exist" 和 "value is of incorrect type"。
edit2:咳咳,else 子句中的打印不正确:(
Is this considered bad?
不,这是完全错误的。您不能像这样组合地图查找和类型断言。
您的代码所做的是:
在地图无条件中查找"key"。如果 "key" 不在映射中,它将产生 nil(因为这是 interface{} 的零值)。
从地图中检索到的值(如果不在地图中则可能为 nil 类型断言为字符串。
您的代码无法确定 "key" 是否在地图中。
你所做的实际上是有效的,因为你使用了 type assertion 的特殊 comma-ok 习惯用法,如果断言不成立,它不会恐慌,并且因为映射可以用不在它(这将导致映射值类型的零值)。
的确,用这个你不能判断键是否在映射中,或者它是但它的值是 nil
,但你已经怀疑这一点好像断言不成立, 你打印 "value does not exist or is not a string".
要测试所有 "corner" 个案例,请参阅此示例:
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)
}
}
输出(在 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:
所以基本上你可以使用它,它不会发生任何坏事(例如恐慌或内存泄漏),只需要知道它的限制(例如你无法获得关联的值对于 "key2"
因为它不是 string
类型)。
如果您的目的是获取键的值(如果它存在且类型为 string
),那么这正是您的代码所做的。尽管您应该避免在需要的地方使用数据结构和构造,因为在大型项目中更难理解和维护。
我的意思是,例如,如果在您的代码中的某个时刻,您希望键 "somekey"
具有关联的 string
值,但它没有,您不会立即知道为什么会这样;是因为地图不包含该键,还是因为它包含但具有错误类型的值(或者该值甚至可能是 nil
)?需要进一步测试/调试以追查根本原因。