想象一下,有人初始化了一個rpc 客戶端,client, _ := rpc.Dial('tcp', 'example.com:port')并且只為您提供了 rpc 客戶端實(shí)例。出于某種原因,您想example.com從客戶端實(shí)例中獲取地址。但是,由于客戶端類型是高度抽象的,您無法直接獲取net.Conn服務(wù)于方法的實(shí)例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這是合理的,因?yàn)樗點(diǎn)odec被聲明為類型ClientCodec,它只是一個具有四個方法簽名的接口。但是,從代碼中,我們知道詳細(xì)類型codec可能是未導(dǎo)出的 struct gobClientCodec。不幸的是,Go 編譯器不夠聰明,無法深入追蹤并找出實(shí)際類型。因此,反射包有沒有辦法告訴編譯器我對codec未導(dǎo)出的類型有信心gobClientCodec?如果這是不可能的,我可能不得不計(jì)算地址偏移量并使用不安全的指針,這是最后的選擇。PSType()反射方法中的默認(rèn)方法不會像codec聲明的那樣工作,ClientCodec并通過在方法中傳遞gobClientCodec結(jié)構(gòu)的地址來初始化,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)不會像編譯器拒絕未導(dǎo)出的類型使用一樣工作。
1 回答

元芳怎么了
TA貢獻(xiàn)1798條經(jīng)驗(yàn) 獲得超7個贊
用于.Elem()
獲取接口中包含的值。
Elem 返回接口 v 包含的值或指針 v 指向的值。如果 v 的 Kind 不是 Interface 或 Ptr,它會發(fā)生恐慌。如果 v 為零,則返回零值。
對于您的特定用例,您還需要使用該unsafe
包來訪問未導(dǎo)出的字段。在使用它之前,請務(wù)必閱讀 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 關(guān)注
- 90 瀏覽
添加回答
舉報(bào)
0/150
提交
取消