Go语言:接口底层对象赋值不生效,如何正确修改其属性值
问题:接口底层结构体赋值后始终保留旧值
尝试通过接口修改其底层结构体的字段值,但修改后原结构体依然保留旧值,示例代码如下:
package main import ( "fmt" "math" ) type Shape interface { Area() float64 } type Circle struct { Radius float64 Name string } func (c Circle) Area() float64 { return math.Pi * c.Radius * c.Radius } type Rectangle struct { Length float64 Width float64 Name string } func (r Rectangle) Area() float64 { return r.Length * r.Width } func assignRadius(s Shape, radius float64, name string) { switch s := s.(type) { case Circle: s.Radius = radius s.Name = name case Rectangle: s.Length = radius s.Name = name } } func main() { var s Shape c := Circle{Radius: 0, Name: "My Circle"} s = c fmt.Println(s.Area()) fmt.Println(c.Radius) fmt.Println(c.Name) assignRadius(s, 10, "My New Circle") fmt.Println(c.Radius) fmt.Println(c.Name) }
原因分析
问题核心是值拷贝:
- 把
Circle值直接赋值给接口变量s时,接口内部存储的是该结构体的副本,而非原对象的引用。 - 在
assignRadius函数中,类型断言case Circle:得到的也是结构体的临时副本,修改的只是这个副本的字段,原结构体完全不受影响。
解决方案
要修改原结构体,必须让接口持有结构体的指针,并且在类型断言时匹配指针类型:
- 将接口变量指向结构体指针:
s = &c而非s = c - 修改
assignRadius中的类型断言分支,匹配指针类型*Circle和*Rectangle - (可选但推荐)将结构体的方法改为指针接收者,避免不必要的值拷贝,同时保持接口实现的一致性
修改后的完整代码:
package main import ( "fmt" "math" ) type Shape interface { Area() float64 } type Circle struct { Radius float64 Name string } // 改为指针接收者 func (c *Circle) Area() float64 { return math.Pi * c.Radius * c.Radius } type Rectangle struct { Length float64 Width float64 Name string } // 改为指针接收者 func (r *Rectangle) Area() float64 { return r.Length * r.Width } func assignRadius(s Shape, radius float64, name string) { switch s := s.(type) { // 匹配指针类型 case *Circle: s.Radius = radius s.Name = name case *Rectangle: s.Length = radius s.Name = name } } func main() { var s Shape c := Circle{Radius: 0, Name: "My Circle"} // 接口存储指针 s = &c fmt.Println(s.Area()) fmt.Println(c.Radius) fmt.Println(c.Name) assignRadius(s, 10, "My New Circle") fmt.Println(c.Radius) // 输出 10 fmt.Println(c.Name) // 输出 My New Circle }
关键改动说明
- 接口持有指针后,类型断言得到的是原结构体的指针,修改指针指向的字段会直接作用于原对象
- 指针接收者的方法允许指针类型实现
Shape接口,同时避免每次调用方法时拷贝结构体,性能更优
内容的提问来源于stack exchange,提问作者smm
相关产品推荐
相关产品推荐

