Go语言中通过引用修改接口值失败的问题及尝试方案
Go接口值的引用修改问题
问题背景
现有一段Go代码,其中库代码不可修改,自定义代码尝试修改Client的transport接口值,但实际输出不符合预期。
库代码(不可修改)
package main import ( "fmt" ) // -------- 库代码,不可修改 ------------ type Client struct { transport RoundTripper } type RoundTripper interface { Do() } type Transport struct{} func (d Transport) Do() {} var DefaultTransport RoundTripper = Transport{}
自定义代码(初始版本)
// -------- 自定义代码,可修改 ------------ func changeTransport(r RoundTripper) { if r == nil { fmt.Println("transport is nil") r = DefaultTransport } } func main() { c := Client{} changeTransport(c.transport) fmt.Println(c.transport) }
实际输出
transport is nil <nil>
预期输出
transport is nil {}
错误尝试的代码
参考方案后尝试了以下修改,但依然报错:
import "log" func changeTransport(r RoundTripper) { if r == nil { fmt.Println("transport is nil") d, ok := DefaultTransport.(Transport) if !ok { log.Fatal("impossible") } if t, ok := r.(*Transport); ok { t = &d fmt.Println("ignoreme", t) } else { log.Fatal("Uff") } } }
实际输出
transport is nil 2009/11/10 23:00:00 Uff
解决方案
要修改Client的transport接口值,需要传递接口指针(*RoundTripper),因为Go中参数是值传递,直接传接口值只会修改副本,无法影响原变量。修改后的自定义代码如下:
// -------- 自定义代码,修改后 ------------ import "log" func changeTransport(r *RoundTripper) { if *r == nil { fmt.Println("transport is nil") *r = DefaultTransport } } func main() { c := Client{} changeTransport(&c.transport) // 传递接口的指针 fmt.Println(c.transport) }
输出结果
transport is nil {}
原理说明
- Go中所有参数都是值传递,包括接口类型。直接传递
RoundTripper接口值时,函数内修改的是接口的副本,不会影响原变量。 - 传递
*RoundTripper(接口的指针)后,函数内通过解引用可以直接修改原接口变量的值,从而将Client的transport赋值为DefaultTransport。 - 错误尝试中的类型断言失败,是因为初始的
c.transport是nil接口,底层没有具体类型,无法断言为*Transport,所以触发了log.Fatal("Uff")。
内容的提问来源于stack exchange,提问作者subtleseeker
相关产品推荐
相关产品推荐

