2016-08-15 1 views
1

У меня есть перечисление в прото-файле, который генерирует целочисленные константы в файле 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

Я не знаю, какой пакет поколения протонов вы используете, но с github.com/golang/protobuf/proto вы также получаете обратное отображение перечислений.

Пример xyz.pb.go сгенерированный файл:

type TimeInterval int32 

const (
    TimeInterval_TI_UNKNOWN TimeInterval = 0 
    TimeInterval_TI_HOUR TimeInterval = 1 
    TimeInterval_TI_DAY  TimeInterval = 2 
    TimeInterval_TI_WEEK TimeInterval = 3 
    TimeInterval_TI_MONTH TimeInterval = 4 
    TimeInterval_TI_QUARTER TimeInterval = 5 
    TimeInterval_TI_YEAR TimeInterval = 6 
) 

var TimeInterval_name = map[int32]string{ 
    0: "TI_UNKNOWN", 
    1: "TI_HOUR", 
    2: "TI_DAY", 
    3: "TI_WEEK", 
    4: "TI_MONTH", 
    5: "TI_QUARTER", 
    6: "TI_YEAR", 
} 
var TimeInterval_value = map[string]int32{ 
    "TI_UNKNOWN": 0, 
    "TI_HOUR": 1, 
    "TI_DAY":  2, 
    "TI_WEEK": 3, 
    "TI_MONTH": 4, 
    "TI_QUARTER": 5, 
    "TI_YEAR": 6, 
} 

func (x TimeInterval) String() string { 
    return proto.EnumName(TimeInterval_name, int32(x)) 
} 
func (TimeInterval) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } 

Так с этим вы можете проверить существование следующим образом:

if _, found := TimeInterval_name[testinputint]; found{ 
    //all ok 
} else { 
    //not a value for this enum 
} 
+0

Да! Я также нашел карту 'X_name' и использую' if _, ok: = X_name [int32 (v)]; ok {return X (v), nil} 'для проверки значений. Btw. если вы хотите получить кредит за этот ответ, вы должны придерживаться примера. И вы уверены в своем утверждении 'found, _'. Думаю, вам нужно написать '_, found' здесь. – Juve

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 
} 

Но, как сказал, это будет только справедливо для перечислений, которые прилипают к правильный йота. Это не может быть случай, когда вы изменили свое перечисление на что-то вроде этого чтения:

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", 
} 

как длина генерируемой карты будет явно меньше, чем шесть :)

Другими словами использовать найденное метод @Ricky_A выше, чтобы оставаться в безопасности.