Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

protoc generates value instead of pointer (Go)

The problem:

I have 2 files in the root directory. I use Makefile to generate Go code from .proto files.

But the language field in the Video struct is a value not a pointer to the value. And the subtitles field in the Video struct is an array of values not an array of pointers to the value.

The question is:

How can I make protoc generate a pointer to the value?

video.pb.go

type Video struct {
    state protoimpl.MessageState
    sizeCache protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields

    Id        string              `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
    Title     string              `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`

    // I need *language.ISO639_1 below
    Languages language.ISO639_1   `protobuf:"varint,3,opt,name=languages,proto3,enum=language.ISO639_1" json:"languages,omitempty"`

    // I need []*language.ISO639_1 below
    Subtitles []language.ISO639_1 `protobuf:"varint,4,rep,packed,name=subtitles,proto3,enum=language.ISO639_1" json:"subtitles,omitempty"`
}

Makefile

gen:
   # Video
   protoc -I. --go_out=plugins=grpc,paths=source_relative:video video.proto

   # Language
   protoc -I. --go_out=plugins=grpc,paths=source_relative:language language.proto

language.proto

syntax = "proto3";

package language;

option go_package = "example.com/group/repo/language;language";

enum ISO639_1 {
    UNKNOWN = 0;
    zh      = 1;
}

video.proto

syntax = "proto3";

package video;

import "language.proto";

option go_package = "example.com/group/repo/video;video";

message Video {
             string            id        = 1;
             string            title     = 2;
             language.ISO639_1 language  = 3;
    repeated language.ISO639_1 subtitles = 4;
}

protoc version: libprotoc 3.11.4

like image 302
Klimbo Avatar asked Jun 08 '26 21:06

Klimbo


1 Answers

Starting in proto3 version 3.12, the field presence feature is supported experimentally, meaning you can again use the optional keyword, similarly to proto2.

You can achieve this by passing a flag --experimental_allow_proto3_optional to protoc when generating the pb.go files (ensure you're running new enough version of protoc and protoc-gen-go to support this experimental feature).

So given this pseudo-.proto file:

enum ISO639_1 {
    UNKNOWN = 0;
    zh      = 1;
}

message Video {
    string            id        = 1;
    string            title     = 2;

    optional ISO639_1 language  = 3;
    repeated ISO639_1 subtitles = 4;
}

You should get generated struct with:

type Video struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields

    Language  *ISO639_1  `protobuf:"varint,3,opt,name=language,proto3,enum=grpctrace.ISO639_1,oneof" json:"language,omitempty"`
    Subtitles []ISO639_1 `protobuf:"varint,4,rep,packed,name=subtitles,proto3,enum=grpctrace.ISO639_1" json:"subtitles,omitempty"`
}

While this solves your issue with the language, I'm not sure you'll be able to work around the repeated field, to get a pointer value. Maybe this thread might be helpful - https://stackoverflow.com/a/25637833/13183366

like image 66
Matej G. Avatar answered Jun 11 '26 10:06

Matej G.