当前位置:首页 > 文章列表 > Golang > Go教程 > Go generate 怎么只对指定包运行代码生成指令

Go generate 怎么只对指定包运行代码生成指令

来源:17golang原创 2026-11-05 08:56:35 0浏览 收藏

我第一次把代码生成接进一个多 package 的 Go 仓库时,最担心的不是生成器本身,而是“明明只改了一个目录,为什么旁边的包也开始生成”。后来我把问题拆成两层:命令行参数决定处理哪些 package,-run 和 -skip 决定这些 package 里的哪些指令真正执行。这样就能把范围收窄到一个明确的包,而不是依赖当前目录的偶然位置。

最直接的写法是给出目标 package 路径,例如 go generate ./internal/schema;如果只想执行某类指令,再加上 -run 或 -skip。Go 官方文档说明,go generate 会按命令行顺序逐个处理 package,并在每个 package 的源文件中按文件名和指令出现顺序执行。

官方文档:https://go.dev/cmd/go/#hdr-Generate_Go_files_by_processing_source

只对指定包运行生成器,先控制命令行里的 package 参数,再控制包内指令筛选;不要把“切换到某个目录”误当成完整的范围策略。

先把“包范围”和“指令范围”分开

go generate 的参数大致有两种职责。package 参数决定扫描哪些包,例如 ./internal/schema、./cmd/tool 或同一目录中的一组 .go 文件;筛选参数决定这些包中哪些原始 //go:generate ... 指令可以执行。

目标常用写法解决的问题
指定一个包go generate ./internal/schema只扫描该 package 所在目录
指定同目录的文件集合go generate ./internal/schema/types.go ./internal/schema/gen.go把文件作为一个 package 处理
只选某类指令go generate -run='stringer' ./internal/schema包不变,只筛选指令文本
排除某类指令go generate -skip='mock' ./internal/schema扫描包,但暂时跳过匹配项
Go generate 从 package 范围到指令筛选的两层作用域说明图
图1:结构说明图,展示 package 参数与 -run、-skip 如何分别收窄 Go generate 的处理范围,不是终端截图。

用 package 路径只处理一个目录

一个 Go package 通常对应一个目录。要让生成器只作用于目标包,最稳妥的方式是从 module 根目录写出相对 package 路径:

# 只处理 schema 包,不把 ./... 扩展到整个模块
go generate ./internal/schema

# 只处理命令行工具包,路径从当前 module 的 go.mod 所在位置解释
go generate ./cmd/catalog

# 先预览将要执行的命令,不真正运行生成器
go generate -n ./internal/schema

这里的 -n 适合放在第一次排查或脚本变更前:它能把将执行的命令打印出来,帮助确认目标 package 没有意外扩大。确认范围后,再去掉 -n 正式运行。

如果写成 go generate ./...,含义就变成匹配 module 下的多个 package。它适合确实要全量生成的场景,不适合“只更新一个包”的日常修改。团队脚本里最好把目标 package 写成显式参数,避免后来新增目录后扩大影响面。

需要更细时,用同目录文件列表限定输入

Go 官方命令还允许把同一个目录中的多个 .go 文件作为一个 package 传入。这个用法适合临时只关注一组源文件,但有一个硬边界:这些文件必须来自同一个目录,不能用跨目录文件列表拼出一个虚构的 package。

# 两个文件来自同一目录,会按一个 package 处理
go generate ./internal/schema/types.go ./internal/schema/gen.go

# 只预览 gen.go 中匹配的生成指令
go generate -n -run='go:generate.*mock' ./internal/schema/gen.go

-run 匹配的是指令的完整原始文本,不是生成器输出文件的名字。为了让筛选可靠,实际项目中可以让不同生成器的指令带有稳定的命令名或参数,例如 stringer、mockgen。不要把筛选规则建立在某个临时绝对路径上,否则换机器后很容易失效。

用 -run 和 -skip 只挑包内的一类生成器

假设一个包里同时有接口代码生成和字符串代码生成:

package schema

// 只对本包的类型生成字符串方法。
//go:generate stringer -type=Status

// 生成接口 mock,命令文本中保留稳定的 mock 关键字便于筛选。
//go:generate mockgen -source=service.go -destination=service_mock_test.go

type Status int

可以这样选择:

# 只执行包含 stringer 的原始指令
go generate -run='stringer' ./internal/schema

# 执行本包的其他指令,但跳过 mock 生成
go generate -skip='mockgen' ./internal/schema

# 同时指定时,命中 -run 又命中 -skip 的指令会被跳过
go generate -run='go:generate' -skip='mockgen' ./internal/schema

注意 -run 和 -skip 的正则匹配对象是完整的原始指令文本,命令行里通常建议加引号,避免 shell 先解释正则字符。两者都设置时,命中两边的指令会跳过;这很适合在统一脚本中保留一个“默认选择集”,再用排除规则临时绕开耗时生成器。

Go generate 按原始 go:generate 指令文本进行 run 和 skip 筛选的说明图
图2:关系说明图,展示原始 go:generate 指令经过 -run 与 -skip 筛选后的执行边界,不是运行结果截图。

注释触发、顺序和失败边界不能忽略

go generate 扫描的是源文件中的指令文本。标准形式是没有前导空格、//go 中间没有空格的 //go:generate command ...。它不会像 Go 编译器那样完整解析语法,因此看起来像指令的注释或多行字符串也可能被当作指令处理,写模板文件时尤其要留意。

package schema

// 正确的生成指令://go 与 :generate 之间不能插入空格。
//go:generate stringer -type=Status

// 这个缩进版本不是推荐的指令写法,避免把格式问题带进团队模板。
//    go:generate stringer -type=Status

执行顺序也会影响结果:多个 package 按命令行顺序处理;同一 package 内,源文件按文件名顺序扫描;同一文件内,指令按出现顺序执行。如果一个生成器返回非零退出状态,当前 package 后面的处理会停止,后续 package 是否继续由命令整体的失败结果决定。因此不要把相互依赖的生成器分散到模糊的通配范围里。

生成器运行时的工作目录是包含指令的 package 源目录。需要引用仓库根目录文件时,优先让生成器使用明确的相对路径约定或环境变量,不要假设所有调用者都会从 module 根目录启动命令。

我的工作流:先预览一个包,再扩大到多个包

我现在会把生成任务分成三步。第一步只给出一个明确 package,并用 -n 看实际命令;第二步用 -run 或 -skip 过滤高成本生成器;第三步确认产物归属后,才把相同规则放进 Makefile、脚本或 CI。这样新增 package 时不会悄悄改变旧脚本的行为。

# 先确认目标包和命令文本
go generate -n ./internal/schema

# 只运行接口相关生成器,避免同时刷新 mock 和字符串代码
go generate -run='mockgen|protoc' ./internal/schema

# 确认无误后,再对两个明确包执行同一组规则
go generate -run='mockgen|protoc' ./internal/schema ./internal/api

如果仓库确实需要全量生成,也建议把 ./... 放在一个名字明确的全量脚本里,而不是让每个开发者把它当成默认命令。对只改一个包的任务,显式路径更容易审查,也更不容易把无关产物混进提交。

相关问题

go generate 会自动被 go build 或 go test 调用吗?

不会。官方文档明确要求显式运行 go generate;构建和测试不会因为存在 //go:generate 注释就自动执行生成器。

只写文件名能跨目录选择多个 package 吗?

不行。文件列表被当成一个 package 处理时应来自同一目录;跨目录需求应改用多个 package 路径,并明确写出处理顺序。

-run 是匹配生成出来的文件名吗?

不是。它匹配的是完整的原始 go:generate 指令文本,所以应围绕稳定的命令名或参数设计规则。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go database/sql 怎么连续读取存储过程返回的多个结果集Go database/sql 怎么连续读取存储过程返回的多个结果集
上一篇
Go database/sql 怎么连续读取存储过程返回的多个结果集
Go sync.Map.CompareAndSwap 返回 false 时怎么判断值已被谁改写
下一篇
Go sync.Map.CompareAndSwap 返回 false 时怎么判断值已被谁改写
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    891次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    891次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    974次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    961次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    785次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码