len对数组、切片、通道分别返回编译期确定的固定长度、切片当前元素个数、缓冲通道中已写未读元素数;len(s)==0不意味着s为nil切片,因非nil切片可长度为0;切片截取仅调整ptr、len、cap三字段,cap表示从当前指针到底层数组末尾的剩余空间;通道len(ch)不可用于安全判断可读性或满状态。

len 对数组、切片、通道返回什么
len 不是方法,而是编译器内建的函数,它不走类型系统,也不调用任何运行时方法。它直接读取变量底层结构中的长度字段——但这个“字段”在不同类型中物理位置和语义完全不同。
对 [5]int 数组:返回声明时固定的长度 5,这个值在编译期就确定,运行时只是硬编码返回;
对 []int 切片:返回其结构体中 len 字段的当前值(即当前元素个数),该字段随 append 或截取操作实时更新;
对 chan int:返回缓冲区中**已写入但尚未被读取**的元素数量,本质是读写指针差值,不是容量也不是总吞吐量。
字符串和 map 同理:len("你好") 返回 6(UTF-8 字节数),len(map[string]int{"a":1}) 返回键值对数量,都是直接查内部计数器,无遍历开销。
为什么 len(s) == 0 不代表 s 是 nil 切片
切片的零值是 nil,此时 len(s) 和 cap(s) 都为 0,但反过来不成立:一个非 nil 切片完全可能 len(s) == 0。
-
s := make([]int, 0)→s != nil,len(s) == 0,cap(s) > 0(通常为 0 或预分配值) -
var s []int→s == nil,len(s) == 0,cap(s) == 0 -
s = s[:0]→ 即使原切片非 nil,截取后仍非 nil 但长度归零
判断是否为 nil 切片,必须显式比较 s == nil,不能只靠 len(s) == 0。否则在 append(s, x) 时会意外创建新底层数组(nil 切片的 append 总是分配),行为与预期不符。
Colly 是一个用于 Go 语言的快速开源爬取和爬虫框架。它适用于从简单的页面提取到异步爬虫处理大量页面集合,支持请求回调和结构化解析。
len 和 cap 在切片截取时怎么变
切片截取 s[i:j] 不分配内存,只调整结构体三字段:ptr 偏移、len 设为 j-i、cap 设为原 cap - i(从新起点到底层数组末尾的剩余空间)。
例如:
arr := [5]int{0,1,2,3,4}
s := arr[1:3] // s = [1 2], len=2, cap=4(索引 1 到 4 共 4 个位置)
t := s[1:2] // t = [2], len=1, cap=3(从索引 2 开始还能塞 3 个)
关键点:
-
cap不是“还能 append 多少”,而是“从当前ptr起,底层数组还剩多少空间” - 即使
len(s) ,<code>append也可能触发扩容——如果底层数组已被其他切片占用部分空间,而你截取的位置靠后,cap小但len更小,看似有余量,实际写入会越界 - 用
s = s[:0]清空切片时,len归零但cap不变,后续append可复用原底层数组
通道的 len(ch) 容易被误解的点
len(ch) 返回的是缓冲区中**待消费元素个数**,不是已发送总数,也不是未读消息队列长度(因为无缓冲通道 len(ch) 永远为 0,无论是否阻塞)。
常见误用场景:
- 用
len(ch) > 0判断通道是否有数据可读 —— 错!因为读操作是原子的,len查询和之间存在竞态,值可能已变 - 认为
len(ch) == cap(ch)表示通道满 —— 对带缓冲通道成立,但对无缓冲通道cap(ch) == 0,len(ch)永远为 0,永远“不满” - 在 select 中依赖
len(ch)控制分支逻辑 —— 编译不报错,但结果不可靠,应改用default或非阻塞接收
真正安全的通道状态判断,只能靠 select + default 或 ch 的阻塞行为本身,而非 <code>len。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










