
go 语言中结构体默认按值传递,若需在函数内修改原始变量并使变更生效,必须传递指针;本文详解如何改造 holder 类型及其使用方式,使其支持任意引用类型值的存储与修改。
go 语言中结构体默认按值传递,若需在函数内修改原始变量并使变更生效,必须传递指针;本文详解如何改造 holder 类型及其使用方式,使其支持任意引用类型值的存储与修改。
在 Go 中,所有参数均按值传递(pass by value),这意味着传入函数的是变量的副本。即使 Holder.Body 是 interface{} 类型,若存入的是 Value 值类型实例(如 Value{Input: 5}),其底层仍为一份独立拷贝;后续对 holder.Body 的类型断言和赋值操作仅作用于该副本,无法影响原始 value 变量。
要实现“修改后主调变量同步更新”,关键在于:传递并持有原始值的地址(即指针)。具体需两处协同改造:
-
调用侧:传入结构体指针
创建value后,应将&value赋给holder.Body,而非value本身:value := Value{Input: 5} holder := Holder{Body: &value} // ✅ 存储指针 -
函数侧:接收 Holder 指针,并对 Body 做指针类型断言
modify函数需接收*Holder,并在内部将Body断言为*Value,再解引用修改字段:func modify(holder *Holder) { valuePtr := holder.Body.(*Value) // 断言为 *Value valuePtr.Result = 2 * valuePtr.Input // 直接修改原结构体字段 }
完整可运行示例:
package main
import "fmt"
type Holder struct {
Body interface{}
}
type Value struct {
Input int
Result int
}
func main() {
value := Value{Input: 5}
holder := Holder{Body: &value} // 存储指向 value 的指针
fmt.Println(value) // {5 0}
modify(&holder) // 传入 holder 的地址
fmt.Println(value) // {5 10} —— 修改已生效
}
func modify(holder *Holder) {
valuePtr := holder.Body.(*Value)
valuePtr.Result = 2 * valuePtr.Input
}⚠️ 注意事项:
-
interface{}本身是值类型,但可安全容纳任意类型的值或指针;关键在于你存入的是什么(值 or 地址)。 - 类型断言
holder.Body.(*Value)在运行时若Body不是*Value,会 panic。生产环境建议使用带 ok 的断言:if valuePtr, ok := holder.Body.(*Value); ok { valuePtr.Result = 2 * valuePtr.Input } else { panic("Body is not *Value") } - 此模式适用于任何需要“透传并修改原始值”的场景,如配置注入、状态容器等,但务必确保生命周期安全——避免存储已失效的栈地址(如局部变量指针被返回到作用域外)。
总结:Go 中没有“引用传递”,只有“传递指针”;Holder 作为通用容器,其灵活性取决于使用者存入的是值还是指针。正确使用指针语义,即可实现预期的原地修改效果。

















