Как сделать обязательным указание одного из двух полей protobuf?

В языке программирования Go для работы с протоколом буферизации сообщений protobuf используется пакет "github.com/golang/protobuf/proto". Для установки этого пакета вы можете выполнить команду:

go get github.com/golang/protobuf/proto

Для того чтобы сделать обязательным указание одного из двух полей в сообщении protobuf, вам нужно воспользоваться опциями "oneof" и "oneof" во время определения сообщения в файле .proto.

Допустим, у вас есть следующее определение сообщения в файле example.proto:

syntax = "proto3";
package example;

message MyMessage {
    oneof data {
        int32 number = 1;
        string text = 2;
    }
}

В этом определении мы объявляем "oneof data", в качестве вариантов которого указаны два поля: "number" с типом int32 и "text" с типом string.

Поле, которое будет задано в сообщении, будет сохранено, а значение другого поля будет сброшено.

Теперь, при генерации кода на Go из этого файла .proto, вы получите структуру с тегом "oneof". Например:

type MyMessage struct {
    Data *MyMessage_Number `protobuf:"bytes,1,oneof,data,1,opt,name=number"`
    // или
    // Data *MyMessage_Text   `protobuf:"bytes,2,oneof,data,2,opt,name=text"`
}

Такая структура данных позволяет вам работать только с одним из двух полей, но не обоими сразу.

Следующий пример кода показывает, как создавать и использовать сообщение, чтобы задать значение одного из двух полей:

package main

import (
    "fmt"

    "github.com/golang/protobuf/proto"
    "github.com/example/examplepb"
)

func main() {
    message := &examplepb.MyMessage{
        Data: &examplepb.MyMessage_Number{
            Number: 42,
        },
    }

    // Преобразование сообщения в бинарное представление
    data, err := proto.Marshal(message)
    if err != nil {
        fmt.Println("Ошибка при маршалинге:", err)
        return
    }

    // Декодирование бинарных данных в сообщение
    decodedMessage := &examplepb.MyMessage{}
    err = proto.Unmarshal(data, decodedMessage)
    if err != nil {
        fmt.Println("Ошибка при декодировании:", err)
        return
    }

    // Вывод значения одного из полей
    if decodedMessage.GetNumber() != 0 {
        fmt.Println("Значение number:", decodedMessage.GetNumber())
    } else if decodedMessage.GetText() != "" {
        fmt.Println("Значение text:", decodedMessage.GetText())
    }
}

В этом примере мы создаем сообщение MyMessage с полем Number, устанавливаем значение 42 и затем преобразуем его в бинарную форму. Затем мы декодируем бинарные данные обратно в сообщение и выводим значение Number.