直接用 net.parsecidr 就行,别自己写解析逻辑;它严格解析标准 cidr(如"192.168.1.0/24"或"2001:db8::/32"),要求 ip 为网络地址、掩码在合法范围(ipv4 0–32,ipv6 0–128),输入非法则返回 nil 和 error,不作容错。

直接用 net.ParseCIDR 就行,别自己写解析逻辑
Go 标准库的 net.ParseCIDR 已经完整支持 CIDR 格式(如 "192.168.1.0/24" 或 "2001:db8::/32")并返回 *net.IPNet,这是最安全、最兼容的做法。自己拆字符串拼掩码容易出错,比如 IPv6 掩码位数越界、IPv4 掩码非连续、忽略网络地址对齐等。
常见错误现象:net.ParseCIDR("192.168.1.1/24") 返回 nil, error —— 因为输入不是网络地址(192.168.1.1 不是 /24 的网络起始地址),但函数本身不自动修正,它只做严格解析。
-
net.ParseCIDR要求输入必须是合法 CIDR 表示:IP 地址 + 斜杠 + 有效前缀长度 - IPv4 前缀长度范围是 0–32,IPv6 是 0–128;超出会报
"invalid CIDR address" - 返回的
*net.IPNet中IP字段是网络地址(已按掩码归零),Mask是对应子网掩码
如果输入不是标准 CIDR(比如只有 IP+掩码字符串),先标准化再调用 ParseCIDR
有些配置源给的是 "10.0.0.1 255.255.255.0" 或 "172.16.0.0 16" 这类非 CIDR 格式。不能硬塞给 net.ParseCIDR,得先转成 "10.0.0.0/24" 这样的形式。
关键点:IPv4 掩码字符串(如 "255.255.255.0")需用 net.IPMask 转成前缀长度;IPv6 掩码不支持点分十进制,只能用前缀长度。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 对
"a.b.c.d m.m.m.m":用net.ParseIP解析 IP,用net.ParseIP解析掩码后转net.IPMask,再调bits := net.IPMask(mask).Size()得到前缀长度 - 对
"x.x.x.x n"(n 是整数):直接拼fmt.Sprintf("%s/%d", ipStr, prefixLen),再喂给net.ParseCIDR - 注意:IPv4 掩码必须是连续高位 1,否则
net.IPMask(mask).Size()会返回 0 —— 这时应报错,而不是强行用
自定义类型嵌入 *net.IPNet 时,注意字段导出和方法继承
如果想封装成自己的类型(比如 type Subnet struct { *net.IPNet }),别漏掉指针嵌入,否则无法继承 *net.IPNet 的所有方法(如 Contains、String)。
容易踩的坑:type Subnet net.IPNet(非指针值嵌入)会导致方法集不匹配,Subnet 实例调用 Contains 会编译失败;而 type Subnet struct { net.IPNet }(值嵌入)虽能调方法,但 IP 和 Mask 字段不可导出,外部无法直接访问或修改。
- 推荐写法:
type Subnet struct { *net.IPNet },然后在构造函数里确保传入非 nil 指针 - 如果需要 JSON 序列化,得为
Subnet实现MarshalJSON—— 因为*net.IPNet默认序列化是{}(空对象) - 不要在结构体里额外存
IP或Mask字段,和嵌入字段重复,易引发一致性问题
测试时重点覆盖边界情况:全 0、全 1、IPv6 /128、/0
net.ParseCIDR 对极端前缀长度是支持的,但业务逻辑未必能处理。比如 "0.0.0.0/0" 匹配所有 IPv4 地址,"::/0" 匹配所有 IPv6 地址,"127.0.0.1/32" 是单主机路由 —— 这些在 ACL、路由匹配、限速策略里很常见,但容易被忽略。
- 写测试用例时,显式验证
subnet.Contains(net.ParseIP("192.168.1.100"))是否符合预期 -
/0网段的IP.Mask是nil,调用Mask.Size()会 panic,要用subnet.Mask != nil先判空 - IPv6 的
/128掩码是 16 字节全 1,net.ParseCIDR("::1/128")返回正常,但某些旧版系统可能不识别这种写法
真正麻烦的不是解析,而是后续怎么用这个 *net.IPNet —— 比如并发读写是否线程安全(它是只读的)、如何高效匹配大量 IP(考虑用前缀树而非遍历切片)、是否要兼容 IPv4-mapped IPv6 地址。这些得看具体场景,标准库只管解析这一步。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










