最可靠的方法是遍历字符串并用 unicode.isdigit 判断每个 rune,它严格匹配 0–9 和全角数字(如 "123"),排除罗马数字、中文数字等,且不误判符号、前导零或溢出情况。

用 unicode.IsDigit 逐字符判断最可靠
直接用 strconv.Atoi 或 strconv.ParseInt 做“能否转成数字”的试探,会误判带符号(如 "-123")、带前导零(如 "007")或超出整型范围的字符串。真正检测“是否全部由数字字符组成”,得回到字符本质:每个 rune 是否都属于 Unicode 数字类。
注意:unicode.IsDigit 比 unicode.IsNumber 更严格——它只认 0–9 和全角数字(如 U+FF10–U+FF19),而后者还会匹配罗马数字、分数、上标等,不适合本场景。
示例写法:
func isAllDigits(s string) bool {
if len(s) == 0 {
return false
}
for _, r := range s {
if !unicode.IsDigit(r) {
return false
}
}
return true
}
-
""返回false,空串不算“全部由数字组成” - 支持 UTF-8 编码的全角数字(如
"123"),但不支持中文数字("一二三")——这符合常规需求 - 不会 panic,也不依赖
strconv的错误路径,性能稳定
strings.TrimLeft + len 判断适合简单 ASCII 场景
如果明确只要处理纯 ASCII 数字(即仅 '0'–'9'),且字符串不长,可以用更轻量的方式:
func isAllDigitsASCII(s string) bool {
if len(s) == 0 {
return false
}
trimmed := strings.TrimLeft(s, "0123456789")
return len(trimmed) == 0
}
这个方法快,但有明显限制:
- 对全角数字(
"123")返回false,因为不在"0123456789"中 - 如果字符串含 NUL 字节或控制字符,
strings.TrimLeft仍会把它们留下,导致误判 - 当输入含大量重复数字(如
"0000000000")时,TrimLeft内部会扫描整个字符串,实际并不比遍历快多少
避免用 strconv.Atoi 做检测的三个坑
常见错误是写成这样:
_, err := strconv.Atoi(s) return err == nil
这会导致三类误判:
-
"-5"和"+42"被认为合法——但它们含非数字字符 -
"0123"在 Go 中是合法整数字符串,但若业务要求“无前导零”,这就错了 -
"99999999999999999999"超出int64范围,Atoi返回 error,但字符串本身全是数字
除非你的真实需求就是“能否无损转成 int”,否则别拿它当字符校验工具。
正则表达式能用但不推荐
写成 ^\d+$ 看似简洁,但要注意:
- Go 的
regexp包中\d默认匹配所有 Unicode 数字(等价于unicode.IsNumber),不是仅 0–9 —— 可能意外接受"Ⅷ"(罗马数字八) - 若改用
^[0-9]+$,就退化为 ASCII-only,且启动正则引擎开销比纯遍历高 3–5 倍 - 编译正则需全局复用
*regexp.Regexp实例,否则每次调用都regexp.Compile是严重性能陷阱
除非已有正则上下文(比如你在批量校验一堆不同模式的字段),否则为单个“全数字”判断引入正则,得不偿失。
真正要兼顾安全、清晰和性能,老老实实遍历 + unicode.IsDigit 是最不容易翻车的选择。别省那几行代码,字符边界才是这类判断的真相所在。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











