Go的net/rpc要求服务必须通过导出结构体及其导出方法暴露,方法签名须严格满足:首字母大写、两个参数(请求结构体指针和响应指针)、唯一error返回值;字段及嵌套类型均需导出才能序列化;不支持接口注册,仅扫描具体类型方法集;跨语言场景应选用gRPC而非net/rpc。

必须用导出结构体 + 导出方法,且签名严格固定
Go 的 net/rpc 不是定义抽象接口(如 type Calculator interface{...}),而是靠结构体实例的导出方法来暴露服务。你写一个 type Arith int 或 type Calculator struct{} 都可以,但关键在方法签名——它必须满足三个硬性条件,否则注册后客户端调用会直接报 method not found 或 invalid method。
- 方法名必须首字母大写(即导出)
- 必须有且仅有两个参数:第一个是接收请求数据的导出结构体(或基础类型),第二个是指向响应结果的指针(也必须是导出类型)
- 返回值必须是
error类型,不能多也不能少
例如这个合法定义:
type Args struct { A, B int }
func (t *Arith) Multiply(args *Args, reply *int) error {
*reply = args.A * args.B
return nil
}而下面这些都会失败:
立即学习“go语言免费学习笔记(深入)”;
-
func (t *Arith) multiply(...)—— 小写方法名,客户端根本看不到 -
func (t *Arith) Multiply(args Args, reply int) error—— 第二个参数不是指针,rpc拒绝序列化 -
func (t *Arith) Multiply(args *Args) (int, error)—— 返回值多了一个int,不匹配协议
字段必须全部导出,且避免嵌套非导出字段
net/rpc 默认用 gob 编码,它只序列化结构体中首字母大写的字段。哪怕你定义了 type Args struct { a, b int },客户端传过去,服务端收到的 args.A 和 args.B 也永远是零值。
更隐蔽的坑是嵌套结构体:
type Inner struct { X int } // ❌ 非导出结构体
type Args struct { Data Inner } // ❌ Data 字段虽导出,但 Inner 不可序列化正确做法是确保所有中间层都导出:
type Inner struct { X int }
type Args struct { Data Inner } // ✅ Inner 是导出类型,且字段 X 大写如果要用 JSON-RPC(比如对接前端),还得额外加 json: tag,否则字段名对不上:
type Args struct {
A int `json:"a"`
B int `json:"b"`
}别把 RPC 接口和 Go 接口混为一谈
有人习惯先写 type Calculator interface { Add(...) ... },再让结构体实现它——这在业务逻辑层没问题,但 net/rpc 完全不认这个接口。它只扫描注册对象的**方法集**,而不是其是否实现了某个 interface。
所以这两者毫无关系:
-
rpc.Register(new(CalculatorImpl))—— 注册的是CalculatorImpl的具体方法 -
var _ Calculator = (*CalculatorImpl)(nil)—— 这行只是编译期校验,对 RPC 调用无影响
如果你真想用 interface 约束实现,建议只用于单元测试或内部抽象,RPC 暴露层仍要按结构体+固定签名来写。
proto 文件才是跨语言 RPC 的事实标准,原生 net/rpc 仅适合 Go 内部通信
如果你的系统未来要支持 Python、Java 或前端调用,或者需要流式传输、拦截器、超时控制等能力,现在就该放弃 net/rpc,改用 gRPC + .proto。因为 net/rpc 的 gob 编码无法被其他语言解析,HTTP 封装(rpc.HandleHTTP())也只是把 gob 包在 HTTP body 里,不是真正的 REST 或 JSON-RPC。
简单对比:
-
net/rpc:快、轻、纯 Go,适合内部微服务间低延迟调用 - gRPC:
protoc自动生成 client/server、天然支持 context、跨语言、流控完备,但引入 protobuf 工具链
真正容易被忽略的一点:很多团队在 proto 里写了 rpc GetUser(...),却忘了生成代码后还要手动实现 UnimplementedUserServiceServer 的方法——没实现的方法默认 panic,不是返回 UNIMPLEMENTED 错误。










