go 中字符串是不可变值类型,函数参数传递为副本,直接交换形参不会影响原始变量;必须通过指针传址才能实现真正的变量交换。
go 中字符串是不可变值类型,函数参数传递为副本,直接交换形参不会影响原始变量;必须通过指针传址才能实现真正的变量交换。
在 Go 语言中,所有基本类型(包括 string)都是
按值传递
的。这意味着当你将字符串变量 a 和 b 作为参数传入 swap 函数时,函数内部接收到的是它们的
独立副本
,对 str1 和 str2 的任何修改(如赋值、交换)都仅作用于栈上的临时变量,不会反映到调用方的原始变量上。
以下代码无法达到交换效果:
✅ 正确做法:使用 *string 指针类型,通过地址间接修改原始变量:
⚠️ 注意事项:
字符串本身是只读的(底层指向不可变字节序列),但
字符串变量是可变的
——你完全可以重新赋值给一个 string 类型的变量(如 a = "new"),这也是指针交换能生效的前提;
不要误以为“字符串不可变”就等于“字符串变量不可修改”,二者概念不同;
若需交换多个字符串或封装复用,可考虑返回新元组:return str2, str1,再由调用方重新赋值(适用于少量变量,且语义更清晰);
对于切片、map、channel 等引用类型,虽默认传“引用语义”,但它们本身仍是值(如 []int 是包含指针、长度、容量的结构体),交换切片变量也需指针,除非你只改其元素而非整个切片头。
总结:Go 的值传递模型要求我们明确区分「数据内容」和「变量容器」。要修改调用方的变量,必须传其地址——这是理解 Go 内存模型与函数交互的关键基础。
func swap(str1, str2 string) {
str1, str2 = str2, str1 // 仅交换副本,无外部影响
}func swap(str1, str2 *string) {
*str1, *str2 = *str2, *str1 // 解引用后交换实际存储位置的值
}
func main() {
a := "World !"
b := "Hello"
swap(&a, &b) // 传入变量地址
fmt.Printf("a=%s\nb=%s\n", a, b)
// 输出:
// a=Hello
// b=World !
}