Setting protobuf properties by name - go

To avoid too much spaghetti style code, I'd like to set certain properties of a golang protobuf object by name. So lets say there's some kind of .proto definition like
syntax = "proto3";
package foo;
message User {
uint64 uid = 1;
string name = 2;
}
and code accessing it like
o := foo.User{Name: "John Doe"}
o.Uid = 40
exists. I'd like to be able to set Uid without the dotted notation. Reflection constructs like
r := reflect.ValueOf(o)
f := reflect.Indirect(r).FieldByName("Uid")
f.SetUint(42)
seem to fail, because Uid is not addressable. I found several posts about struct fields not being addressable, but it's still unclear (to me as a "golang newbie") what has to be done in this context to make it work.

You need to pass a pointer to o to reflect.ValueOf. By simply passing the value, the fields of the struct will not be addressable.
r := reflect.ValueOf(&o)
f := reflect.Indirect(r).FieldByName("Uid")
f.SetUint(42)
If at all possible, however, I would try to implement this without reflection. Either use a map in your protocol buffer definition, or a switch in your Go code:
switch name {
case "Uid":
o.Uid = uintValue
case "Name"
o.Name = stringValue
}
The non-reflect code is less likely to fail at runtime.

Related

Is there a way to extract a protobuf oneof int value?

TL;DR: In Go, is there any way to get the integer value of a protobuf oneof case?
Detail:
In C# I can easily query the integer value of a Oneof case using something like the following:
opcode = (int)ChannelMessage.ChannelActionOneofCase.Register; // opcode will equal 1
However in Golang, there does not appear to be anything that I can use to easily extract that integer value.
I know that I can switch on the type itself:
switch m.ChannelAction.(type) {
case *proto.ChannelMessage_Register:
...
however in my case this will require me to unmarshal every message, which for certain types isn't strictly necessary since I'm required to send the opcode along every time.
If it's helpful, my ChannelMessage type looks like the following:
message ChannelMessage
{
oneof ChannelAction
{
ChannelRegister register = 1;
ChannelUnregister unregister = 2;
...
}
}
It's probably not what you want to actually do, but the google.golang.org/protobuf/reflect/protoreflect package does have the necessary functions, if you need to refer to the field numbers of the fields that are part of your oneof.
For example, assuming you've imported your protos as pb, to get the number 1 by name (as in your C# example) you can do:
desc := (&pb.ChannelMessage{}).ProtoReflect().Descriptor()
opcode := desc.Fields().ByName("register").Number()
(This isn't strictly specific to the oneof, since oneof fields are really just regular message fields with an additional constraint that only one of them may be set.)
Or to figure out which field number a oneof field is set to in message m without writing out a type switch, assuming you know one of them has definitely been set, you can do:
ref := m.ProtoReflect()
desc := ref.Descriptor()
num := ref.WhichOneof(desc.Oneofs().ByName("ChannelAction")).Number()
In both cases the result (opcode, num) will be a numeric type (protoreflect.FieldNumber = protowire.Number) that has an underlying type of int32 you can convert it to.
You are right, you can do that with type switch:
// my example used simple strings instead of custom messages.
example := proto.ChannelMessage{
ChannelAction: &pbExample.ChannelMessage_Register{"foobar"},
}
t := example.GetChannelAction()
switch v := t.(type) {
case *pbExample.ChannelMessage_Register:
fmt.Printf("register\n")
case *pbExample.ChannelMessage_Unregister:
fmt.Printf("unregister\n")
default:
fmt.Printf("I don't know about type %T!\n", v)
}
// what you also can do is to ask directly your oneOf case and try to typecast it.
val, ok := example.GetRegister().(int) // GetUnregister is other option.
if ok {
// black magic happens here
}

Can I get a variable of a type based on reflect.Type [duplicate]

I have a function which takes an interface, like this:
func method(data interface{})
.. because I need to process different structs which have common fields/methods. In this function I use data tens or hundreds of times, in different places. It's really unpleasant to add switch a.(type) { case .. case .. all the time.
Is there a way to create a variable with just one switch with needed type and then just use this variable everywhere later? Something like:
var a .... // something here
switch data.(type) {
case *Struct1:
a = data.(*Struct1)
case *Struct2:
a = data.(*Struct2)
}
// Continue with 'a' only
a.Param = 15
fmt.Println(a.String())
Go is a statically typed language, the type of a must be known at compile time. And since Go does not support generics yet, you can't do what you want.
Try to come up with some other solution, e.g. abstract away the things you want to do with a into an interface, and have the concrete types implement that interface. Then a can be a variable of this interface type, and you can call methods of it.
If you can achieve this, actually you can even change the parameter of the data type to this interface, and no type assertion or type switch is needed.
Alternatively you could use reflection to access common fields (either for get or set) identified by their name, but reflection provides no compile-time guarantee, and it's usually less efficient. For an example how to do that, see this question: Assert interface to its type
You can't do what you ask for in your question directly, go is statically typed, so you can't have one variable that can hold different types, and still access that variable as if it is typed.
If you're only working on the common struct fields in your method, you are perhaps better off gathering all the common variables in its own struct, illustrated below as the commons struct and have your method take that type as an argument
package main
import (
"fmt"
)
type commons struct {
name string
age int
}
type structA struct {
commons
other_stuff int
}
type structB struct {
commons
foo string
}
func method(c* commons) {
fmt.Println(c)
c.age +=1
}
func main() {
a := structA{commons{"foo", 44}, 1}
b := structB{commons{"bar", 33}, "test"}
method(&a.commons)
method(&b.commons)
fmt.Println(a)
}
Go playground
I can't figure out what is your real goal but if the "method" you want to write handles common fields from similar structures, and you cannot fix original structures using Type Embedding, as #nos said above, then you can try to make another structure for method-internal use:
var v Vehicle // with common fields
switch data.(type) {
case *Car:
v.Handle = data.(*Car).Handle // or CircleHandle
case *Motorcycle:
v.Handle = data.(*Motorcycle).Handle // or BarHandle
}
v.Degree = 15
v.Speed = 50
v.Direction = "left"
v.Style = "rough"
/// so many things on `v`...
steering(v)
I think it is not a good approach but sometimes... :-)

How to create a variable with needed type instead of type assertion

I have a function which takes an interface, like this:
func method(data interface{})
.. because I need to process different structs which have common fields/methods. In this function I use data tens or hundreds of times, in different places. It's really unpleasant to add switch a.(type) { case .. case .. all the time.
Is there a way to create a variable with just one switch with needed type and then just use this variable everywhere later? Something like:
var a .... // something here
switch data.(type) {
case *Struct1:
a = data.(*Struct1)
case *Struct2:
a = data.(*Struct2)
}
// Continue with 'a' only
a.Param = 15
fmt.Println(a.String())
Go is a statically typed language, the type of a must be known at compile time. And since Go does not support generics yet, you can't do what you want.
Try to come up with some other solution, e.g. abstract away the things you want to do with a into an interface, and have the concrete types implement that interface. Then a can be a variable of this interface type, and you can call methods of it.
If you can achieve this, actually you can even change the parameter of the data type to this interface, and no type assertion or type switch is needed.
Alternatively you could use reflection to access common fields (either for get or set) identified by their name, but reflection provides no compile-time guarantee, and it's usually less efficient. For an example how to do that, see this question: Assert interface to its type
You can't do what you ask for in your question directly, go is statically typed, so you can't have one variable that can hold different types, and still access that variable as if it is typed.
If you're only working on the common struct fields in your method, you are perhaps better off gathering all the common variables in its own struct, illustrated below as the commons struct and have your method take that type as an argument
package main
import (
"fmt"
)
type commons struct {
name string
age int
}
type structA struct {
commons
other_stuff int
}
type structB struct {
commons
foo string
}
func method(c* commons) {
fmt.Println(c)
c.age +=1
}
func main() {
a := structA{commons{"foo", 44}, 1}
b := structB{commons{"bar", 33}, "test"}
method(&a.commons)
method(&b.commons)
fmt.Println(a)
}
Go playground
I can't figure out what is your real goal but if the "method" you want to write handles common fields from similar structures, and you cannot fix original structures using Type Embedding, as #nos said above, then you can try to make another structure for method-internal use:
var v Vehicle // with common fields
switch data.(type) {
case *Car:
v.Handle = data.(*Car).Handle // or CircleHandle
case *Motorcycle:
v.Handle = data.(*Motorcycle).Handle // or BarHandle
}
v.Degree = 15
v.Speed = 50
v.Direction = "left"
v.Style = "rough"
/// so many things on `v`...
steering(v)
I think it is not a good approach but sometimes... :-)

Why would we use blank identifiers in Go?

I'm finding the use of the blank identifier a little hard to understand. I've looked at effective go and understand most of the use cases they describe but then looking at a tutorial I came across this in a route handler function:
var person Person
_ = json.NewDecoder(req.Body).Decode(&person)
in the first line we create a new empty variable of type Person (a struct previously defined) and then I assume that
&person is passing the person var in by reference,
to be filled with data by the Decode function
this function then goes on to perform a few more tasks before encoding and returning a json response.
Why do we need have the decode assigned to a blank identifier? Couldn't we just run json.NewDecoder(req.Body).Decode(&person) ? if we can't, why not?
I'm assuming you're learning golang and asking because you can't identify why this example used this practice.
As #JimB mentioned in comments, the example writer didn't need to do this they're simply ignoring the Error return.
The blank identifier _ can be used to strictly provide the keys in a struct too. See this for reference
Without enforcing
type SomeStruct struct {
FirstField string
SecondField bool
}
myStruct := SomeStruct{"", false}
Enforcing to mention the key for the value (Removes the dependency of ordering the values)
type SomeSturct struct {
FirstField string
SecondField bool
_ struct{}
}
// COMPILATION ERROR
myStruct := SomeSturct{"", false}
The above will give the error too few values in SomeSturct literal

Instantiating a struct via name using a string in go

I am trying to create a function that takes a []byte and an interface{} (standing for the struct) and returns an interface{} as the struct type passed into the func.
Something like this:
package main
import (
"encoding/json"
)
func UnmarshalFromJSONArray(sms []byte,tt string) (interface{}) {
var ts = new(tt)
err := json.Unmarshal(sms,&ts)
if(err != nil) {
fmt.Println(err)
}
return sms
}
So that method would run something like this:
// let's say a struct has the following definition:
type MyStructType struct {
Id int
Name string
Desc string
}
// we can some how get its fully qualified class name (this may require reflection?) or pass it into the UnMarshal method direction some how.
mst := "package.MyStructType",
// and then assume a byte array ba that has JSON format for
ba := []byte(`{"Id":"3","Name":"Jack","Desc":"the man"}`)
stct := UnmarshalFromJSONArray(ba,mst)
MyStructureType out := stct
// leaving "stct" being the unmarshalled byte array which can be used like any other struct of type "MyStructureType"
The key being that I never need to know what the fields of MyStructureType are before unmarshalling. All I need are the name of the struct and some way to instance one and then populate it with JSON byte array data that matches its fields. Hopefully that is possible (it is trivial in java using reflection). So I want to basically unmarshal an anonymous struct type by it's name without needing to know what fields it has.
Any suggestions?
The short answer is that this is impossible. There is no string to type translator in Go. You can make a map of strings to reflect.Type's, but you would need to know the possible options ahead of time or you need to provide the caller with a way to register types (perhaps in init).
Assuming you have found a way to resolve the string to its reflect.Type, you can simply call reflect.New(typ).Interface() to get the pointer you need to pass to json.Unmarshal().
The best answer is to avoid trying this all together. Writing idiomatic Java in Go isn't really possible. If I knew more about your problem, I could give you a more idiomatic Go solution.

Resources