想象一下,有人初始化了一個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 關注
- 86 瀏覽
添加回答
舉報
0/150
提交
取消