想象一下,有人初始化了一个rpc 客户端,client, _ := rpc.Dial('tcp', 'example.com:port')并且只为您提供了 rpc 客户端实例。出于某种原因,您想example.com从客户端实例中获取地址。但是,由于客户端类型是高度抽象的,您无法直接获取net.Conn服务于方法的实例RemoteAddr()。在这种情况下,反射包可能会有所帮助。让我们从以下尝试开始:func getRemoteAddr(client *rpc.Client) net.Addr { codec := reflect.Indirect(rpclient).FieldByName("codec") connV := codec.FieldByName("rwc") conn := connV.Interface().(net.Conn) return conn.RemoteAddr()}然而,第二行立即跳出一个错误:panic: reflect: call of reflect.Value.FieldByName on interface Value这是合理的,因为它codec被声明为类型ClientCodec,它只是一个具有四个方法签名的接口。但是,从代码中,我们知道详细类型codec可能是未导出的 struct gobClientCodec。不幸的是,Go 编译器不够聪明,无法深入追踪并找出实际类型。因此,反射包有没有办法告诉编译器我对codec未导出的类型有信心gobClientCodec?如果这是不可能的,我可能不得不计算地址偏移量并使用不安全的指针,这是最后的选择。PSType()反射方法中的默认方法不会像codec声明的那样工作,ClientCodec并通过在方法中传递gobClientCodec结构的地址来初始化,NewClient如下所示:func NewClient(conn io.ReadWriteCloser) *Client { encBuf := bufio.NewWriter(conn) client := &gobClientCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(encBuf), encBuf} return NewClientWithCodec(client)}此外,reflect.TypeOf(rpc.gobClientCodec)不会像编译器拒绝未导出的类型使用一样工作。
1 回答
元芳怎么了
TA贡献1798条经验 获得超7个赞
用于.Elem()
获取接口中包含的值。
Elem 返回接口 v 包含的值或指针 v 指向的值。如果 v 的 Kind 不是 Interface 或 Ptr,它会发生恐慌。如果 v 为零,则返回零值。
对于您的特定用例,您还需要使用该unsafe
包来访问未导出的字段。在使用它之前,请务必阅读 unsafe 的文档。
func getRemoteAddr(client *rpc.Client) net.Addr { rv := reflect.ValueOf(client) rv = rv.Elem() // deref *rpc.Client rv = rv.FieldByName("codec") // get "codec" field from rpc.Client rv = rv.Elem() // get the value that ClientCodec contains rv = rv.Elem() // deref *gobClientCodec rv = rv.FieldByName("rwc") // get "rwc" field from gobClientCodec conn := *(*net.Conn)(unsafe.Pointer(rv.UnsafeAddr())) return conn.RemoteAddr()}
https://go.dev/play/p/cHHdwQJ7DE7
- 1 回答
- 0 关注
- 71 浏览
添加回答
举报
0/150
提交
取消