go 函数和方法参数均按值传递,若方法需修改接收者状态(如向切片追加元素),必须使用指针接收者;否则操作仅作用于副本,原结构体不变。
在 Go 中,c.fields 在 Define 方法调用后“变空”或“未保留新增元素”,根本原因在于 方法接收者被错误地定义为值类型而非指针类型。虽然 c.fields 是一个切片(本身是引用类型),但 c 作为结构体实例,在值接收者下仍是整个结构体的副本。因此,对 c.fields = append(c.fields, f) 的赋值操作,修改的是副本中的 fields 字段,而原始结构体的 fields 字段完全不受影响。
以下是最小可复现问题的对比示例:
❌ 错误写法(值接收者):
func (c CliPrompter) Define(f *Field) { // 注意:无 *
fmt.Printf("before: %+v\n", c.fields)
c.fields = append(c.fields, f) // 修改的是 c 的副本!
fmt.Printf("after: %+v\n", c.fields)
}
即使 append 成功扩展了副本的切片底层数组,c.fields 的地址和长度变化也不会反映到调用方的原始 CliPrompter 实例上——因为 c 是独立拷贝。
✅ 正确写法(指针接收者):