
go 中切片本身是引用类型,但其底层数组指针、长度和容量封装在结构体中;若需在函数内修改切片头(如重分配)或其元素并使变更反映到调用方,需显式传递切片的指针(*[]t),且访问时必须先解引用。
go 中切片本身是引用类型,但其底层数组指针、长度和容量封装在结构体中;若需在函数内修改切片头(如重分配)或其元素并使变更反映到调用方,需显式传递切片的指针(*[]t),且访问时必须先解引用。
在 Go 中,切片([]string)是一个包含三个字段的结构体:指向底层数组的指针、长度(len)和容量(cap)。这意味着对切片元素的修改(如 s[i] = x)默认可被调用方看到——但前提是未发生扩容导致底层数组地址变更。然而,一旦函数内执行了 append 或重新赋值(如 s = append(s, "new")),原切片变量可能指向新数组,此时调用方无法感知变更,除非你传递的是切片的指针。
要确保任何修改(包括元素更新、重分配、甚至替换整个切片)都能反馈给调用方,必须使用 *[]T 类型,并在函数内显式解引用:
func process(names *[]string) {
fmt.Println("Pre process:", *names) // 解引用后打印切片内容
(*names)[1] = "modified" // ✅ 正确:先解引用,再索引赋值
}
⚠️ 关键点:*[]string 是“指向切片的指针”,不是“指向字符串的指针”。运算符优先级中,* 的优先级高于 [],因此 names[1] 会被解析为 (*names)[1] 的误写(实际是 (*names)[1] 才合法),而直接写 names[1] 会报错:invalid operation: names[0] (type *[]string does not support indexing)。
完整可运行示例:
package main
import "fmt"
func process(names *[]string) {
fmt.Println("Pre process:", *names)
(*names)[1] = "modified" // 修改第二个元素
// 也可安全重分配:*names = append(*names, "chani")
}
func main() {
names := []string{"leto", "paul", "teg"}
process(&names)
fmt.Println("Post process:", names) // 输出: [leto modified teg]
}
✅ 小结:
- 若仅需修改现有元素(不改变 len/cap),传
[]string即可(切片本身已含底层数组指针); - 若需修改切片头信息(如
append后让调用方看到新长度/新底层数组),必须传*[]string并解引用操作; - 始终牢记:
*names得到切片值,(*names)[i]才能索引;避免遗漏括号导致编译错误。
这种显式指针语义体现了 Go “明确优于隐含”的设计哲学——修改可观察状态,必须有清晰的语法信号。










