go语言无法禁止函数修改参数,只能通过值传递隔离、只读通道约束和类型设计收口;基本类型和数组传值天然只读,string是只读值类型,小struct传值更轻量,大struct宜用指针并明确文档契约,切片和map传参实为传描述符副本,内容可被修改,需封装暴露只读方法,append操作不改变原切片,真只读需返回新副本。

Go 语言中无法“禁止”函数修改参数,因为语言本身不提供参数只读修饰符(如 const);真正可控的只有「传什么」和「怎么用」——靠值传递隔离、用只读通道约束、靠类型设计收口。
传值是默认的只读防线
对基本类型(int、string、struct)和数组,直接传值就能天然防止外部被改。函数拿到的是副本,改了也白改。
-
string是只读值类型:哪怕传&s进去,函数内也不能改底层字节数组;s = "new"只是重赋值局部变量 - 小
struct(比如两个int字段)传值比传指针更轻量,没解引用开销,也杜绝意外修改 - 大
struct(含切片字段或几十个字段)传值成本高,此时宁可接受「可修改」风险,也要用指针——但得在文档里写清契约
[]T 和 map[K]V 不是只读的,别被表象骗
传 []int 或 map[string]int 进函数,看起来像“传引用”,其实是传描述符副本。副本里的指针仍指向原底层数组或哈希表,所以 s[0] = x 或 m["k"] = v 会生效。
- 想阻止内容被改?不能靠传参方式,得靠封装:把切片/映射包进结构体,只暴露只读方法(如
Get(i int) T),不暴露索引或赋值能力 -
append是陷阱:函数内s = append(s, x)可能分配新底层数组,外部完全看不到变化——这不是只读,是“失效的修改” - 真要强制只读语义,只能返回新副本:
return append([]int{}, s...),但代价是额外分配
只读通道 是少数带编译时只读保障的机制
通道类型支持方向标注:chan(只写)、<code>(只读)。传 <code> 给函数,编译器会拒绝任何发送操作。
- 函数签名写成
func consume(,调用方必须传入可转为只读通道的值(比如普通 <code>chan int或另一个) - 接收方只能用
,不能写 <code>c ,否则编译报错:<code>invalid operation: cannot send to receive-only channel - 注意:只读通道不能转回双向通道,但双向通道可安全转为只读——这是单向转换,无运行时开销
没有银弹,只有分层控制
Go 不提供 const 参数,也不允许接口方法标记只读。所谓“防止修改”,本质是组合策略:对简单数据靠值传递,对集合类靠封装+文档契约,对并发通信靠通道方向限制。最容易被忽略的是——即使用了 ,接收方仍可能把收到的值存下来再改;真正的只读,最终落在数据本身的不可变性上,而不是传参那一刻。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











