- Published on
GO返回参数结构体是否该用指针
在 Go 语言中,决定一个方法是否应该返回一个结构体的指针(如 *pb.GreetResponse)或是直接返回结构体(如 pb.GreetResponse)通常取决于几个因素,包括性能、内存使用和函数的预期用途。让我们来看看这两种方法的应用场景:
返回 pb.GreetResponse(结构体实例):
- 当返回的结构体是小的或者中等大小时,直接返回结构体可能更高效,因为它减少了内存分配(避免了在堆上创建对象)和垃圾回收的开销。
- 如果函数的调用者通常不需要修改返回的结构体,或者你想确保返回的数据不会被外部修改(因为 Go 中结构体是按值传递的),那么返回结构体实例会更合适。 在结构体内容比较小的情况下,按值返回可以减少解引用的需要,从而提高访问速度。
返回 *pb.GreetResponse(结构体指针):
- 当结构体较大时,返回指针更高效,因为它减少了数据复制的开销。这是因为返回指针只需要复制内存地址,而不是整个结构体。
- 如果函数的调用者可能需要修改返回的结构体,那么返回指针会更合适,因为结构体指针允许调用者直接修改原始结构体。
- 当涉及到接口实现或多态时,通常使用指针,因为结构体可能需要实现某些接口,而接口方法通常是通过指针接收者来定义的。
- 在使用指针时,你还可以返回 nil 来表示某些特殊情况,比如错误或“无值”情况,这在返回结构体实例时无法做到。
如果 pb.GreetResponse 是一个较大的结构体或者你希望调用者能够修改返回的数据,或者你的方法需要实现某个接口,那么返回 *pb.GreetResponse 可能更合适。如果这个结构体相对较小,并且你想要保证返回的数据不会被修改,那么返回 pb.GreetResponse 可能更好。
比如grpc生成的pb.go中,因为GreetResponse使用指针接受者方法,所以返回结构体指针更合适。
// 指针方法 func (x *GreetResponse) Reset() { *x = GreetResponse{} if protoimpl.UnsafeEnabled { mi := &file_greeter_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } }
Server处实现Hello
func (g *GreeterService) Hello(ctx context.Context, in *pb.GreetRequest) (*pb.GreetResponse, error) { log.Printf("Name: %s", in.GetName()) return &pb.GreetResponse{Message: "Hello: " + in.GetName()}, nil }