4/06/2025

new和make的用法及len和cap的用法

 

一、内存分配函数对比

1. new(Type)

go
复制
ptr := new(int) // 返回 *int 指针
*ptr = 10
  • 特点

    • 分配零值内存,返回指针

    • 适用于所有类型(包括基本类型和复合类型)

    • 对复合类型不初始化底层结构(如 new([]int) 会创建 *[]int 指向 nil 切片)

2. make(Type, len, cap)

go
复制
s := make([]int, 3, 5)  // 长度3,容量5的切片
m := make(map[string]int) // 需省略cap参数
ch := make(chan int, 5)   // 缓冲通道容量5
  • 特点

    • 仅用于 slice/map/channel 的初始化

    • 分配内存并初始化底层数据结构(如切片的指针数组、哈希表桶等)

    • map 初始化时 cap 参数会被忽略(建议省略)


二、容量与长度函数

1. cap() 适用类型

类型含义示例
array等于数组长度(编译时确定)cap([3]int{}) → 3
slice底层数组最大可扩展长度cap(make([]int,2,5)) → 5
channel缓冲区容量(非元素数量)cap(make(chan int,5)) →5

2. len() 适用类型

类型含义示例
array元素数量(编译时确定)len([3]int{}) → 3
slice当前存储元素数量len(make([]int,2,5)) → 2
channel缓冲区中待读取元素数量ch <- 1; len(ch) →1
string字节数(非字符数)len("中文") →6
map键值对数量len(map[int]bool{1:true})→1

三、核心类型特性

1. 数组 (Array)

go
复制
var arr [3]int // 长度和容量固定为3
  • 编译期确定:长度是类型的一部分([3]int ≠ [5]int

  • 值传递:赋值或传参时进行全量拷贝

2. 切片 (Slice)

go
复制
s := make([]int, 2, 5) // len=2, cap=5
s = append(s, 3)       // len=3, cap=5(无需扩容)
  • 动态扩展:当 append 超容量时,按 2 倍策略扩容(直到 1024 后按 1.25 倍)

  • 底层共享:切片操作(如 s[1:3])共享同一数组,修改影响原数据

  • 反射修改(高风险操作):

    go
    复制
    sHeader := (*reflect.SliceHeader)(unsafe.Pointer(&s))
    sHeader.Len = 4 // 强制修改长度(可能导致越界)

3. 字符串 (String)

go
复制
str := "中文"
byteLen := len(str)          // 字节数 → 6
charCount := len([]rune(str)) // 字符数 → 2
  • 不可变性:字符串内容无法直接修改,需转 []byte 或 []rune

4. 通道 (Channel)

go
复制
ch := make(chan int)    // 无缓冲通道(cap=0)
bufferedCh := make(chan int, 5) // cap=5
  • 无缓冲通道:发送和接收操作同步阻塞

  • 有缓冲通道

    • len(ch) 表示当前缓冲元素数量

    • cap(ch) 表示缓冲区最大容量


四、易错点与技巧

  1. 切片初始化对比

    go
    复制
    var s1 []int          // nil 切片(len=0, cap=0)
    s2 := make([]int, 0)  // 空切片(底层数组指针非nil)
  2. 通道容量规范

    go
    复制
    make(chan int, 5) // ✅ 正确:容量参数单独指定
    make(chan int)    // ✅ 正确:默认容量0(无缓冲)
  3. 字符串遍历

    go
    复制
    str := "Hello, 世界"
    for i, r := range str { 
        // i → 字节索引,r → Unicode 字符
    }

Go语言无名指针类型及其作用

  在 Go 语言中, 无名指针类型(Unnamed Pointer Type)   指的是直接通过指针语法(如   *int 、 *string )声明的指针类型,而不是通过   type   关键字显式命名的类型(如   type IntPtr *int )。它的核心作用是简...