go中无真正引用类型,只有值传递;值类型如int、struct、[3]int,类引用类型如slice、map、chan等因含指针而表现类似引用。

Go 里哪些类型是值类型,哪些是引用类型?
Go 没有传统意义上的“引用类型”概念——它只有值传递,但某些类型底层持有指针,行为上像引用。别被“引用类型”这个词带偏:决定是否共享数据的,不是类型名,而是它内部是否包含指针(或是否被编译器隐式转为指针操作)。
常见值类型:int、float64、bool、struct(不含指针字段时)、[3]int(数组);
常见“类引用”类型:slice、map、chan、func、*T、interface{}(非空且底层是引用类型时)。
注意:struct 是值类型,但如果它字段里有 slice 或 map,复制 struct 只会浅拷贝这些字段的 header(即长度、容量、底层数组指针),数据仍共享。
立即学习“go语言免费学习笔记(深入)”;
-
map和slice的 header 是小结构体(比如slice是三个 word:data ptr / len / cap),传参时复制的是这个 header,不是底层数组 -
[1024]int是值类型,传参会复制全部 1024 个 int,开销大,应优先用[]int -
string是只读的 header 类型(data ptr + len),行为类似引用,但不可修改,所以安全
函数传参时修改不生效?先看传的是什么
这是最常踩的坑:以为传了 map 就能改原数据,结果发现函数里 delete(m, "k") 确实生效;但换成 struct{ m map[string]int } 再传进去,s.m["k"] = 1 却不影响调用方——因为 struct 是值类型,s 被复制了,s.m header 虽然指向同一底层数组,但 s 本身是副本。
Dbsite企业网站管理系统V1.5.0 秉承"大道至简 邦达天下"的设计理念,以灵巧、简单的架构模式构建本管理系统。可根据需求可配置多种类型数据库(当前压缩包支持Access).系统是对多年企业网站设计经验的总结。特别适合于中小型企业网站建设使用。压缩包内包含通用企业网站模板一套,可以用来了解系统标签和设计网站使用。QQ技术交流群:115197646 系统特点:1.数据与页
真正决定能否修改原数据的,是“你操作的对象是否指向同一块底层内存”,而不是“类型叫什么”。
- 直接传
map[string]int:可以增删改,因为 header 中的 data 指针没变 - 传
struct{ Data []int },然后在函数里做s.Data = append(s.Data, 1):调用方看不到新元素,因为append可能分配新底层数组,而s是副本,赋值只改了副本的 header - 想确保修改生效,统一用指针:
*MyStruct,或直接传[]int(header 复制不影响 append 后的共享性,但要小心扩容时机)
用 make 和 new 初始化时的区别在哪?
new(T) 返回 *T,把内存置零,适用于所有类型,但对 slice/map/chan 没用——它们需要额外初始化才能用;make(T, args...) 只用于 slice、map、chan,返回的是值(不是指针),且完成底层资源分配。
-
new([]int)返回*[]int,解引用后是[]int{}(nil slice),不能直接append -
make([]int, 0)返回可立即使用的空 slice,底层数组已分配(或延迟分配) -
new(map[string]int)是错的,编译失败;make(map[string]int)才对 - 自定义 struct 中含
map字段,new(MyStruct)得到的 map 字段仍是 nil,需手动m.MapField = make(map[string]int)
interface{} 接收值时,底层到底是值还是指针?
取决于你传进去的是什么。interface{} 是一个两字宽结构体(type ptr + data ptr),它会把值“装箱”:如果传的是 int,就复制该 int;如果传的是 *MyStruct,就复制那个指针;如果传的是 map[string]int,就复制它的 header。
这导致一个经典陷阱:用 interface{} 存 struct 值,再用 reflect.ValueOf().Addr() 取地址会 panic,因为值不在堆上,无法取地址。
- 传
MyStruct{}给fmt.Println,里面拿到的是副本,改它不影响原变量 - 传
&MyStruct{},interface{} 存的是指针,后续反射操作可寻址 -
json.Unmarshal要求传指针,就是因为需要修改调用方变量;若传值,反序列化结果只存在副本里
值类型和引用类型不是 Go 的语法分类,而是你和内存打交道的方式。关键永远是:你持有的是数据本身,还是通向数据的路标——而路标是否唯一,得看它指向哪儿、有没有人也在用它。









