1、引用类型与值类型的区别
-
值类型:存储数据的值。
-
引用类型:存储数据的内存地址。
1.1、值类型
值类型主要包含:
-
基本数据类型(如
int
、float
、bool
、string
、struct
等)
1.2、引用类型
引用类型包括:
-
切片(slices)
-
Map映射(maps)
-
通道(channels)
-
接口(interfaces)
-
函数(functions)
2、初始化差异
2.1、new
通常使用 new
去初始化值类型( int
、float
、bool
、string
、struct
)并返回指向类型零值的指针。
package main
import (
"fmt"
)
type Person struct {
Name string
Age int
}
func main() {
// 使用 new 创建一个 int 类型的指针
numPtr := new(int)
*numPtr = 42
fmt.Println(*numPtr) // 输出: 42
// 使用 new 创建一个 Person 类型的指针
pPtr := new(Person)
pPtr.Name = "Alice"
pPtr.Age = 30
fmt.Println(*pPtr) // 输出: {Alice 30}
}
虽然也可以使用 new
初始化引用类型,但只会为其分配内存并返回指针,不会初始化底层数组,因此返回的值不能直接使用,通常不建议使用new初始化。
p := new([]int)
fmt.Println(*p == nil) // 输出 true
(*p)[0] = 1 // 运行时错误:panic: runtime error: index out of range
2.2、make
因为引用类型的复杂的内部结构,通常使用 make
去初始化引用类型,make
不仅会为其分配内存,还会对底层结构进行初始化,并返回一个已经初始化的数据结构本身。
slice := make([]int, 5)// 创建一个长度为 5 的整型切片
myMap := make(map[string]int)// 创建一个map映射数组
ch := make(chan int)// 创建一个通道
3、开发中的内存申请优化
预分配容量:在数组长度可预知的情况下,尽量指定初始容量以减少动态扩容的开销。
// 预分配长度为 0,容量为 100 的 slice
s := make([]int, 0, 100)
// 预分配容量为 100 的 map
m := make(map[string]int, 100)
避免在循环中重复调用 make
或 new
:这样会造成 GC(垃圾回收)的压力,尽量复用内存。
//原型:
package main
import (
"fmt"
)
type Data struct {
Value int
}
func main() {
// 分配内存
data := new(Data)
for i := 0; i < 10; i++ {
data.Value = i // 修改值
// 处理数据
fmt.Println(data.Value)
}
}
4、总结
-
引用类型 和 值类型 的主要区别在于它们存储数据的方式。
-
使用
make
初始化引用类型时,会分配内存并初始化底层数据结构。 -
使用
new
初始化值类型时,仅分配内存并返回指针,不会初始化底层数据结构。 -
在开发中,合理预分配容量和避免重复内存分配可以有效减少 GC 压力,提升程序性能。