我有map[string]string
,我需要测试是否存在某些键,如果存在,则将某些值转换为整数。例如:
m := map[string]string{"a": "b", "c": "d", "e": "f"}
if v1, ok := m["a"]; ok {
if v2, ok := m["c"]; ok {
if i1, err := strconv.Atoi(v1); err != nil {
if i2, err := strconv.Atoi(v2); err != nil {
// do something with i1, i2
}
}
}
}
我发现自己的想法是:
if m.exists("a") && m.exists("c") && is_int(m["a"]) && is_int(m["c"]) {
// do something with atoi(m["a"]) and atoi(m["c"])
}
...但是使用Go的标准库并不方便。那么,Go的做法是什么?
答案 0 :(得分:4)
测试string
值是否为数字并将其转换为数字基本上是相同的工作量。
所以我宁愿使用以下的util函数,除了检查键和测试值之外,还返回转换后的数字:
func getInts(m map[string]string, keys ...string) (is []int, err error) {
for _, k := range keys {
v, ok := m[k]
if !ok {
return is, fmt.Errorf("%s is missing", k)
}
var i int
if i, err = strconv.Atoi(v); err != nil {
return
}
is = append(is, i)
}
return
}
用3种不同的情况进行测试:
maps := []map[string]string{
{},
{"a": "b", "c": "d", "e": "f"},
{"a": "1", "c": "2", "e": "f"},
}
for _, m := range maps {
if is, err := getInts(m, "a", "c"); err == nil {
fmt.Println("Numbers:", is)
} else {
fmt.Println("Error:", err)
}
}
输出(在Go Playground上尝试):
Error: a is missing
Error: strconv.Atoi: parsing "b": invalid syntax
Numbers: [1 2]
答案 1 :(得分:2)
一种方法是创建自己的map[string]string
类型并添加一些简单的方法。这是一个简单的例子:
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
}
您可以使用以下内容将map[string]string
转换为mapExists
m := map[string]string{
"a": "b",
"c": "2",
}
m2 := mapExists(m)
然后调用你的例子中的东西:
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"))
将输出:
a exists: true
asd exists: false
a isInt: false
c isInt: true
这是“最佳”还是“惯用”方式是一个意见问题,取决于具体情况。一般来说,我(个人)更愿意不使用这些包装器。您可以将上面的示例重写为以下内容:
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
}
}
我认为这更具可读性。它更冗长,但Go是一种冗长的语言; - )
但同样,它取决于整个代码库。如果您经常调用此模式,那么自定义类型可能是一个很好的解决方案(代价是性能略低,这可能是也可能不是问题)。