Go:将整数安全地转换为协议缓冲区枚举值的最佳实践

时间:2016-08-15 14:34:58

标签: go enums type-conversion protocol-buffers

我在proto文件中有一个枚举,它生成pb.go文件中的整数常量。我现在有一些来自外部数据源的整数,并希望将它们安全地映射到可能的常量。

以下是我目前所拥有的内容:https://play.golang.org/p/-5VZqPbukd

package main

import (
    "errors"
    "fmt"
)

//enum in the proto file
//
// enum X {
//    A = 0;
//    B = 1;
//    C = 2;
//    D = 3;
// }

//enum type generated by protoc
type X int32

//enum constants generated by protoc
const (
    X_A X = 0
    X_B X = 1
    X_C X = 2
    X_D X = 3
)

func intToX(v int) (X, error) {
    x := X(v)
    switch x {
    case X_A, X_B, X_C, X_D:
        return x, nil
    }
    return 0, errors.New("could not convert int to X")
}

func main() {
    for i := -1; i < 10; i++ {
        if x, err := intToX(i); err != nil {
            fmt.Println("unhandled error:", err, "for input value", i)
        } else {
            fmt.Printf("%d => X(%d)\n", i, x)
        }
    }
}

问题:是否有更好的,更惯用的方法将传入的整数值映射到protoc生成的常量?

特别是,我想避免在case A, B, C, D语句中明确列出所有常量。

1 个答案:

答案 0 :(得分:0)

是的,因为@RickyA提到使用范围很好,因为它验证了所有可能的底层const值。

此外,您可以检查枚举的长度,但这只有在基础枚举值没有任何“间隙”的情况下才有可能。并且有一个连续的数字范围。

通过代码详细说明:

typelength := int32(len(TimeInterval_name))
if testinputint < 0 || int32(testinputint) >= typelength {
    // not a value for this enum, return err
}

稍微冗长一点,只使用int而不是int32

if testinputint < 0 || int(testinputint) >= len(TimeInterval_name) {
    // not a value for this enum, return err 
}

但是如上所述,这只适用于坚持适当的iota的枚举。当你改变你的枚举来读取这样的东西时可能不是这样的:

var TimeInterval_name = map[int32]string{
    0: "TI_UNKNOWN",
    1: "TI_HOUR",
    2: "TI_DAY",
    3: "TI_WEEK",
    // we do not use month anymore 4: "TI_MONTH",
    5: "TI_QUARTER",
    6: "TI_YEAR",
}

因为生成的地图的长度明显少于6:)

换句话说,使用上面找到的@Ricky_A方法来保证安全。