使用Micro框架开发网关,如何通过反射修改pbValue实例?
pbStruct to pbValue After ctx.ShouldBind(&pbStruct)? Problem Description
I'm working on a new project with the Micro framework, having wrapped up GRPC-related development. Now I need to build a gateway to interact with the frontend. To avoid redundant coding, I'm using the auto-generated structs and init functions from protoc in my pb.go file. Here's a snippet of the generated code:
type AuthLoginReq struct { Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } func init() { proto.RegisterType((*AuthLoginReq)(nil), "device.info.provider.service.AuthLoginReq") }
I referenced an article about creating struct instances from strings and wrote this code to instantiate the proto struct:
// api.go qiniuType := proto.MessageType("device.info.provider.service.AuthLoginReq") pbValue := reflect.New(qiniuType) pbStruct := pbValue.Elem().Interface()
But here's the issue: after running ctx.ShouldBind(&pbStruct), pbStruct updates with the new data, but pbValue stays unchanged. How can I get pbValue to reflect these changes?
Solution
The core problem here is that pbStruct is a value copy of the struct referenced by pbValue.Elem(). When you pass &pbStruct to ctx.ShouldBind(), you're modifying this isolated copy instead of the original struct instance that pbValue points to.
Here are two simple fixes:
1. Bind Directly to the Original Pointer (Recommended)
reflect.New(qiniuType) returns a reflect.Value that represents a pointer to your proto struct. You can pass this pointer directly to ctx.ShouldBind(), which modifies the original instance directly and keeps pbValue in sync automatically:
qiniuType := proto.MessageType("device.info.provider.service.AuthLoginReq") pbValue := reflect.New(qiniuType) // Bind directly to the original pointer from pbValue if err := ctx.ShouldBind(pbValue.Interface()); err != nil { // Replace with your actual error handling logic log.Fatalf("Binding failed: %v", err) } // pbValue now holds the updated data updatedStruct := pbValue.Elem().Interface()
2. Sync the Modified Copy Back to the Original
If you must work with pbStruct first, you can use reflect.Copy() to transfer the updated data from the copy to the original instance referenced by pbValue:
// After running ctx.ShouldBind(&pbStruct) reflect.Copy(pbValue.Elem(), reflect.ValueOf(pbStruct))
This works because pbValue.Elem() gives you the reflect.Value of the original struct, while reflect.ValueOf(pbStruct) gives you the value of the modified copy. reflect.Copy() handles transferring the data between them.
Why Your Original Code Failed
When you call pbValue.Elem().Interface(), you're creating a copy of the struct value (since AuthLoginReq is a value type). Any changes to this copy via &pbStruct don't affect the original struct that pbValue points to. Using the pointer from pbValue.Interface() skips the copy step, letting you modify the original instance directly.
内容的提问来源于stack exchange,提问作者Papandadj

