Как установить перечисление protobuf2 с помощью golang - PullRequest
0 голосов
/ 22 мая 2018

Я пытаюсь использовать перечисления protobuf2 в golang, но не могу понять.

Я создал простой файл protobuf:

syntax         =          "proto2" ;
package                    enum    ;
message Foo{
     enum Bar{
         LOL = 1;
     }
     optional Bar baz = 1;
}

И я создал простой файл golang:

package main

import (
    enum "./enum"
    "github.com/golang/protobuf/proto"
)

func main() {
    msg := &enum.Foo{
        Baz: enum.Foo_LOL,
    }
    proto.Marshal(&msg)
}

Я получил ошибку.

./foo.go:10: cannot use enum.Foo_LOL (type enum.Foo_Bar) as type *enum.Foo_Bar in field value

Казалось, что решение достаточно просто, просто добавьте & перед enum.Foo_Bar.

package main

import (
    enum "./enum"
    "github.com/golang/protobuf/proto"
)

func main() {
    msg := &enum.Foo{
        Baz: &enum.Foo_LOL,
    }
    proto.Marshal(&msg)
}

Нет:

./foo.go:10: cannot take the address of enum.Foo_LOL

Я искал в Google и нашел этого парня, которого троллирует бот .У него был какой-то рабочий код, но он был достаточно многословен, чтобы утомлять библейского ученого:

package main

import (
    enum "./enum"
    "github.com/golang/protobuf/proto"
)

var lolVar = enum.Foo_LOL

func main() {
    msg := &enum.Foo{
        Baz: &lolVar,
    }
    proto.Marshal(msg)
}

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

package main

import (
    enum "./enum"
    "github.com/golang/protobuf/proto"
)

func main() {
    msg := &enum.Foo{
        Baz: enum.Foo_LOL.Enum(),
    }
    proto.Marshal(msg)
}

Какой метод предназначен?

1 Ответ

0 голосов
/ 22 мая 2018

Protobuf с syntax="proto2" создает поля перечисления с типом указателя, поэтому Foo.baz будет иметь тип *Foo_Bar.Вы не можете присвоить этому полю не указатель Foo_Bar, а только значение указателя.

Кроме того, значения перечисления, которые вы перечисляете в файлах protobuf, будут сгенерированы как константы в Go.И вы не можете получить адрес постоянных значений, подробности см .: Найти адрес постоянной в go

Если ваш protobuf генерирует метод Enum(), возвращающий указатель на значение, то этохорошо, вы можете использовать это.Но этот метод не всегда генерируется, поэтому не удивляйтесь, если вы не найдете его для какого-либо типа / enum.

Если он отсутствует, самый простой - это создать (локальную) переменную, и чейадрес, который вы можете взять:

lol := enum.Foo_LOL
msg := &enum.Foo{
    Baz: &lol,
}
err := proto.Marshal(msg)

Если вам приходится делать это много раз / много раз, создайте вспомогательную функцию, которая отвечает цели метода Enum().Вот как вы можете создать его:

func barPtr(b enum.Foo_Bar) *enum.Foo_Bar { return &b }

И используя его:

msg := &enum.Foo{
    Baz: barPtr(enum.Foo_LOL),
}
err := proto.Marshal(msg)

Есть много других опций для получения указателя на целочисленный тип, но они не обязательно более чистыеили более эффективный.Вы можете увидеть список различных методов здесь: Как мне сделать литерал * int64 в Go?

...