Dictionary 测试和处理地图中多个键的惯用方式是什么?

Dictionary 测试和处理地图中多个键的惯用方式是什么?,dictionary,go,Dictionary,Go,我有一个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);

我有一个
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
       }
     }
  }
}
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"))
我发现自己的思路是:

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的标准库并不方便。那么,怎么做呢?

一种方法是创建自己的
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]字符串
转换为
map exists

m := map[string]string{
    "a": "b",
    "c": "2",
}

m2 := mapExists(m)
然后调用示例中的内容:

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
       }
     }
  }
}
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是一种冗长的语言;-)


但同样,这取决于整个代码库。如果您经常调用此模式,则自定义类型可能是一个很好的解决方案(代价是性能稍低,这可能是问题,也可能不是问题)。

测试
字符串是否是数字,并将其转换为数字的工作量基本相同

因此,我宁愿使用下面的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)
    }
}
输出(在上尝试):