如何使用反射获得未导出的类型?

想象一下,有人初始化了一个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)不会像编译器拒绝未导出的类型使用一样工作。


慕侠2389804
浏览 72回答 1
1回答

元芳怎么了

用于.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
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go