Go scanner.Scanner.ErrorCount 怎么统计源码词法错误
来源:17golang原创
时间:2026-10-04 20:17:13 355浏览 收藏
用 go/scanner 做源码词法扫描时,统计错误的关键不是数 token.ILLEGAL,而是让 Scanner 完整扫描到 token.EOF,再读取 s.ErrorCount。如果还需要展示行列和原因,就在 Init 时传入 scanner.ErrorHandler,把它作为明细通道。
官方地址:https://pkg.go.dev/go/scanner
ErrorCount统计扫描期间遇到的错误,初始化和每次扫描都可能触发错误处理。Scan为了尽量继续工作,可能在发生错误后仍返回看起来合法的 token。- 计数负责判定是否通过,
ErrorHandler负责保存位置和消息,两者不要混为一个指标。
先把错误计数绑定到一次完整扫描
Scanner.Init 会重新初始化扫描器,并把 ErrorCount 清零。源字节长度必须与 token.File 的大小一致,否则初始化会 panic。下面的写法把错误明细放进切片,最终用计数做机器判断:
package main
import (
"fmt"
"go/scanner"
"go/token"
)
func main() {
// 故意放入非法字符和未闭合注释,演示错误计数与明细收集。
src := []byte("package demo\nfunc main() { @ }\n/*")
fset := token.NewFileSet()
file := fset.AddFile("demo.go", fset.Base(), len(src))
var s scanner.Scanner
var details []string
s.Init(file, src, func(pos token.Position, msg string) {
// handler 只保存诊断信息,不负责替代 ErrorCount。
details = append(details, fmt.Sprintf("%s: %s", pos, msg))
}, 0)
for {
// 必须持续取 token,直到 EOF,错误才会被完整发现。
_, tok, _ := s.Scan()
if tok == token.EOF {
break
}
}
fmt.Printf("errors=%d, details=%d\n", s.ErrorCount, len(details))
for _, detail := range details {
fmt.Println(detail)
}
}
这里的 errors 应在扫描结束后读取。不要在第一次 Scan 后就判断,因为后续 token 仍可能触发错误;也不要把 details 的长度当成通用计数契约,业务若修改了 handler(例如过滤或合并消息),它就不再等于原始错误数。
为什么不能只数 token.ILLEGAL

Scan 返回 token.ILLEGAL 时,字面量通常是触发问题的字符,但词法错误不只表现为这个 token。未闭合的块注释、格式不完整的字面量等情况,也可能先通过错误处理器报告,再尽量返回可继续处理的 token。因此,正确的通过条件应是 s.ErrorCount == 0,而不是“没有看到 ILLEGAL”。
这也是 ErrorHandler 的价值:它接收 token.Position 和消息,适合输出文件名、行号、列号;ErrorCount 则是稳定的汇总值,适合让批处理任务返回失败状态。两条通道同时保留,既能定位问题,也不会依赖 token 恢复策略。
把统计口径和复用边界说清楚

有三个边界容易在工具代码里被忽略:
- 只统计一次:在同一个
Scanner上重复调用Scan不会重新产生一轮结果;需要重新扫描时再次调用Init,它会清零计数。 - 错误去重另算:如果按每行只保留一条错误,应使用自己的集合或
scanner.ErrorList.RemoveMultiples;这改变的是展示列表,不是扫描器本身的ErrorCount。 - 注释不是错误统计开关:需要把注释作为 token 取出时启用
scanner.ScanComments,它只改变注释处理方式,不会把已有词法错误变成普通 token。
最终可以把结果封装成两个字段:Count 用于门禁,Diagnostics 用于反馈。调用方只关心是否通过时读取计数;编辑器或命令行需要高亮时再消费明细。
常见误区与判断方法
问:ErrorHandler 没有传入,能不能统计?
可以。传入 nil 时不会收到明细回调,但 ErrorCount 仍会递增。
问:扫描结果里没有 ILLEGAL,是否就代表源码没有词法错误?
不代表。扫描器会尽量恢复并继续返回 token,最终仍应检查 ErrorCount。
问:什么时候读取计数最稳妥?
完成循环并收到 token.EOF 后读取;若初始化阶段就触发错误,计数也会包含在这次扫描结果里。
-
466 收藏
-
447 收藏
-
133 收藏
-
246 收藏
-
123 收藏
-
422 收藏
-
194 收藏
-
168 收藏
-
197 收藏
-
152 收藏
-
Golang · Go教程 | 4小时前 | 标准库 · HTTP服务 · Go教程 · 可观测性 · Go expvar expvar.Publish 运行指标 expvar.Func debug vars466 收藏
-
127 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习